-1

I don't know how to describe the goal I want to achieve with a good title. I have a list of objects where each have a boolean member. I want to filter this list to get at the end the first objects from the list which all have this boolean member set to true.

This is how I would do it without streams, add every object to a new list for which the getter method returns true and stop when the first element returns false.

int i = 0;
while(i < list.size()){
    if(!list.get(i).isMemberTrue()){
        break;
    }
    else{
        newList.add(list.get(i));
    }
    i++;
}

Is this somehow possible with a sequential stream?

Sartorius
  • 499
  • 5
  • 12
Semaphor
  • 900
  • 2
  • 12
  • 33
  • `list.stream().filter(member->member::isMemberTrue).findFirst()` – bananas Sep 29 '16 at 06:38
  • one more thing if anyhow your first `member` from list is not member your loop will `break` so make sure what you are doing – bananas Sep 29 '16 at 06:45
  • Yes the resulting list may be empty in case the first object returns already false. – Semaphor Sep 29 '16 at 06:46
  • 1
    As you can see from the answers, you have found a case where switching to streams over the classic loop does *not* make sense. All solution attempts (so far) either use intermediate objects, give up potential parallelism, or iterate through the list multiple times. My advice is: stick to your loop. – mtj Sep 29 '16 at 07:54

3 Answers3

0

Maybe something like this would work:

ArrayList<YourClass> newList = new ArrayList<>(
    list.stream()
   .filter(obj -> obj.isMemberTrue())
   .collect(Collectors.toList())
);

remember to import java.util.stream.Collectors if you want to return it as a list.

Cicero
  • 2,872
  • 3
  • 21
  • 31
0

you can use this code to get list

list.subList(0,list.indexOf(list.stream()
                    .filter(member->!member::isMemberTrue)
                    .findFirst()
                    .orElse(list.size()))

or you can use it as

int endIndex=list.indexOf(list.stream()
                    .filter(member->!member::isMemberTrue)
                    .findFirst()
                    .orElse(list.size());

then

list.sublist(0,endIndex);

In this I am getting new list by making use of List::sublist(..)and then I am usinglambda` to fetch all members before the condition goes false.

After being reviewed by Flown, I updated the answer Hope this helps! :)

Community
  • 1
  • 1
bananas
  • 1,176
  • 2
  • 19
  • 39
  • 2
    findFirst() will give you the object, not the index. So you'd have to actually use sublist(0, list.indexOf(firstObject)), provided that such a first object exists. – mtj Sep 29 '16 at 07:52
  • @mtj thanks for pointing out, I'll make the edit – bananas Sep 29 '16 at 07:59
  • 1
    @AsteriskNinja This should do your job: `int low = IntStream.range(0, list.size()).filter(i -> !list.get(i).isMemberTrue()).findFirst().orElse(0);`. But be careful, if the underlying implementation isn't a `RandomAccess` list. – Flown Sep 29 '16 at 08:08
  • @flown what if list passes `filter(..)` then your code will result `0` as low which is not needed instead one can use `orElse(list.size()`) – bananas Sep 29 '16 at 08:26
  • @AsteriskNinja you're right. It should be `.orElse(list.size());`. – Flown Sep 29 '16 at 09:05
-1

You can achieve the solution with streams. Just remember the predecessor in the list.

public class ListTest
{

    @Test
    public void test()
    {

        List<Foo> list = new ArrayList<>();
        list.add(new Foo(true));
        list.add(new Foo(true));
        list.add(new Foo(true));
        list.add(new Foo(false));
        list.add(new Foo(false));
        list.add(new Foo(true));
        list.add(new Foo(true));


        List<Foo> firstSequence = list.stream().filter(new Predicate<Foo>() {

            private boolean inFirstSequence = true;

            @Override
            public boolean test(Foo foo)
            {
                // turns into false, if first false value is found
                inFirstSequence = inFirstSequence && foo.b;

                return inFirstSequence;                
            }
        }).collect(Collectors.toList());

        Assert.assertEquals(3, firstSequence.size());
    }

    private class Foo
    {
        public Foo(boolean b)
        {
            super();
            this.b = b;
        }

        boolean b = true;
    }
}
Dangermouse
  • 290
  • 1
  • 3
  • 11
  • 1
    Have you tried your code in parallel execution? Are you getting the same results? I guess not. So please don't use a state in a stateless expression since unexpected behavior can occur. – Flown Sep 29 '16 at 07:44
  • @Flown. Thanks, for review. If i put the property to class ListTest I will agree with you. So the state is only used in the call stack of method test() ?!? – Dangermouse Sep 29 '16 at 08:38
  • You can see an example why you shouldn't use state in `Stream` pipeline in the [documentation](https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#Statelessness) – Flown Sep 29 '16 at 09:03