8
\$\begingroup\$

I am trying to remove empty a String array from ArrayList:

 List<String[]> someList = new ArrayList<String[]>();

which contains data like:

[
 { "Loic" , "Remy" , "Fail","Medical"} ,
 { "Faser" , "Foster" , "Pass","Southampton","GK","Young"} ,
 { "" , "" ,} ,
 { "" , "" , "","","",""} ,
 { "Emre" , "Can" , "Pass","Liverpool","CDM"}
]

I want to remove the empty String[] from the ArrayList:

List<String[]> someList = (List<String[]>) csvMappedData.get(Constants.CSV_DATA);
 //Clone to new Array List
 List<String[]> cloneCSV = new ArrayList<String[]>(someList);
 for (String[] csvSingleLine : cloneCSV) {
 //Create New List of String only
 List<String> strings = new ArrayList<String>(Arrays.asList(csvSingleLine));
 //Remove all string that are null or blank
 strings.removeAll(Arrays.asList(null, ""));
 //Check if the List is empty or null after removing in above step
 if (strings.isEmpty() || Validator.isNull(strings)) {
 //If yes it is all blank String array 
 //Remove from orginal LIST
 someList.remove(csvSingleLine);
 }
 }

The above code is working fine for me.

Questions:

  1. Is there any other alternative solution that is quick and elegant?
  2. What are the change that I could make to it, to make it more efficient?

The size of each row varies, so I couldn't use remove all by creating a dummy array.

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Aug 12, 2014 at 8:30
\$\endgroup\$
3
  • 2
    \$\begingroup\$ I'd like to mention, that the excessive commenting actually makes this less readable. \$\endgroup\$ Commented Aug 12, 2014 at 15:17
  • \$\begingroup\$ Yes, in my development environment, i don't use comments that often....except for the javadoc. But i commented it out here so , i can elaborate what i have done in the code. \$\endgroup\$ Commented Aug 12, 2014 at 15:46
  • \$\begingroup\$ @Runcorn We can always see what you are doing, the code will tell us that. Your comments should explain why you are doing it. \$\endgroup\$ Commented Aug 12, 2014 at 19:05

2 Answers 2

10
\$\begingroup\$

There are a few tricks you can use to improve this code.

First of all,

List<String[]> someList = (List<String[]>) csvMappedData.get(Constants.CSV_DATA);
List<String[]> cloneCSV = new ArrayList<String[]>(someList);
for (String[] csvSingleLine : cloneCSV) {

I understand that you're using this "copy the list"-approach to avoid a ConcurrentModificationException, but instead of doing that you can use an Iterator.

List<String[]> someList = (List<String[]>) csvMappedData.get(Constants.CSV_DATA);
Iterator<String[]> iterator = someList.iterator();
while (iterator.hasNext()) {
 String[] strings = iterator.next();
 if (stringsShouldBeRemoved) {
 iterator.remove();
 }
}

Now, as for your code to check for whether to remove a String[]:

List<String> strings = new ArrayList<String>(Arrays.asList(csvSingleLine));
strings.removeAll(Arrays.asList(null, ""));
if (strings.isEmpty() || Validator.isNull(strings)) {
 someList.remove(csvSingleLine);
}

Again, you're using a copying-approach. To check for whether or not an object fulfills a criteria, you don't need to copy it, modify it, and check if it fulfills another criteria. Copying it and modifying it makes it slower and uses more memory.

Instead, let's use a method:

boolean shouldRemoveCSVSingleLine(String[] csvSingleLine) {
 for (String str : csvSingleLine) {
 if (str != null && !str.equals("")) {
 return false;
 }
 }
 return true;
}

Now you can use this method in the while(iterator.hasNext()) loop:

List<String[]> someList = (List<String[]>) csvMappedData.get(Constants.CSV_DATA);
Iterator<String[]> iterator = someList.iterator();
while (iterator.hasNext()) {
 String[] strings = iterator.next();
 if (shouldRemoveCSVSingleLine(strings)) {
 iterator.remove();
 }
}
answered Aug 12, 2014 at 9:02
\$\endgroup\$
2
  • \$\begingroup\$ Thanks @Smion , i agree with you in the most of the reasoning you stated , except for checking the empty array. for (String str : csvSingleLine) { , wouldn't it be better to use csvSingleLine.removeAll(Arrays.asList(null, "")); ? \$\endgroup\$ Commented Aug 12, 2014 at 9:18
  • \$\begingroup\$ @Runcorn That depends, if you have the data { "Faser", "Foster", "Pass", "", "", "Young"} would you want it to be modified into { "Faser", "Foster", "Pass", "Young"} ? \$\endgroup\$ Commented Aug 12, 2014 at 9:22
5
\$\begingroup\$

The removal code can be done in 1 line using the Java 8 Stream API, though I'm sure Simon's answer has better performance.

static List<String[]> removeEmptyStringArrays(List<String[]> strArrays) {
 return strArrays
 .stream()
 .filter(strArray -> !isEmptyStringArray(strArray))
 .collect(Collectors.toList());
}
static boolean isEmptyStringArray(String[] strArray) {
 for(String str : strArray) {
 if(str != null && !str.equals("")) {
 return false;
 }
 }
 return true;
}
answered Aug 12, 2014 at 17:16
\$\endgroup\$
2
  • \$\begingroup\$ You could just write if (!"".equals(str)) { return false; }. \$\endgroup\$ Commented Aug 12, 2014 at 18:31
  • 3
    \$\begingroup\$ Speaking of Java 8, it's even possible to do return Arrays.stream(args).allMatch(!"".equals(str)); in the isEmptyStringArray method, which makes it easier to inline it inside the .filter lambda directly. \$\endgroup\$ Commented Aug 12, 2014 at 19:04

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.