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:
- Is there any other alternative solution that is quick and elegant?
- 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.
-
2\$\begingroup\$ I'd like to mention, that the excessive commenting actually makes this less readable. \$\endgroup\$Cruncher– Cruncher2014年08月12日 15:17:24 +00:00Commented 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\$Runcorn– Runcorn2014年08月12日 15:46:12 +00:00Commented 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\$Simon Forsberg– Simon Forsberg2014年08月12日 19:05:17 +00:00Commented Aug 12, 2014 at 19:05
2 Answers 2
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();
}
}
-
\$\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 usecsvSingleLine.removeAll(Arrays.asList(null, ""));
? \$\endgroup\$Runcorn– Runcorn2014年08月12日 09:18:17 +00:00Commented 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\$Simon Forsberg– Simon Forsberg2014年08月12日 09:22:31 +00:00Commented Aug 12, 2014 at 9:22
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;
}
-
\$\begingroup\$ You could just write
if (!"".equals(str)) { return false; }
. \$\endgroup\$200_success– 200_success2014年08月12日 18:31:38 +00:00Commented 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 theisEmptyStringArray
method, which makes it easier to inline it inside the .filter lambda directly. \$\endgroup\$Simon Forsberg– Simon Forsberg2014年08月12日 19:04:07 +00:00Commented Aug 12, 2014 at 19:04