Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

String list get an item starting without loop

I have a array list contains thousands of data.

For Example:

List<String> custNames = new ArrayList<String>();
custNames.add("John");
custNames.add("Tom");
custNames.add("Bart");
custNames.add("Tim");
custNames.add("Broad");

Now I want to get count of names only starting with 'T'. I used looping mechanism for my solution.

List<String> filterNames = new ArrayList<String>();
String nameStarts="T";
for(int i=0;i<custNames.size();i++)
{
    if(custNames.get(i).toLowerCase().startsWith(nameStarts.toLowerCase()))
    {
        filterNames.add(custNames.get(i));
    }
}
System.out.println(filterNames.size());

But I have very large collection of data in this custNames list. Is there any different solution without using loop?

Thanks.

like image 799
Joy16 Avatar asked Oct 15 '16 12:10

Joy16


2 Answers

There is very good solution from Java 8 for your problem.

Try this,

long filterNameCount = custNames
        .stream()
        .parallel() 
        .filter((s) -> s.startsWith(nameStarts.toLowerCase()))
        .count();

System.out.println(filterNameCount);
like image 119
Kushan Avatar answered Oct 05 '22 01:10

Kushan


If you are open to using a third-party library, there are a few interesting options you could use with Eclipse Collections.

If you use the ArrayList as you have it above, you can use the LazyIterate utility as follows:

int count = LazyIterate.collect(custNames, String::toLowerCase)
        .countWith(String::startsWith, nameStarts.toLowerCase());
Assert.assertEquals(2, count);

If you use the Eclipse Collections replacement for ArrayList, you can use the rich functional protocols available directly on MutableList:

MutableList<String> custNames =
        Lists.mutable.with("John", "Tom", "Bart", "Tim", "Broad");
String nameStarts= "T";
int count = custNames.asLazy()
        .collect(String::toLowerCase)
        .countWith(String::startsWith, nameStarts.toLowerCase());
System.out.println(count);
Assert.assertEquals(2, count);

The serial API in Eclipse Collections is eager-by-default, which is why I called asLazy() first. The collect method would otherwise create another MutableList.

If you benchmark your code with your full set of data, the following parallel version of the code may be more performant:

MutableList<String> custNames =
        Lists.mutable.with("John", "Tom", "Bart", "Tim", "Broad");
String nameStarts= "T";
int processors = Runtime.getRuntime().availableProcessors();
int batchSize = Math.max(1, custNames.size() / processors);
ExecutorService executor = Executors.newFixedThreadPool(processors);
int count = custNames.asParallel(executor, batchSize)
        .collect(String::toLowerCase)
        .countWith(String::startsWith, nameStarts.toLowerCase());
executor.shutdown();
Assert.assertEquals(2, count);

The asParallel() API in Eclipse Collections is lazy-by-default. The API forces you to pass in a an ExecutorService and an int batchSize. This gives you complete control over the parallelism.

You can also use the Stream API with all MutableCollections in Eclipse Collections because they extend java.util.Collection.

Note: I am a committer for Eclipse Collections.

like image 22
Donald Raab Avatar answered Oct 04 '22 23:10

Donald Raab