Java stream - Get objects of consecutive same field [duplicate] - java

This question already has answers here:
Limit a stream by a predicate
(19 answers)
Closed 6 years ago.
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?

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.

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! :)

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;
}
}

Related

Unable to get my head around Predicate isEqual method

In Java docs it is given -
Modifier and Type Method and Description
static <T> Predicate<T> isEqual(Object targetRef)
Returns a predicate that tests if two arguments are equal according to Objects.equals(Object, Object).
In https://www.geeksforgeeks.org/java-8-predicate-with-examples/
it is given -
isEqual(Object targetRef) : Returns a predicate that tests if two arguments are equal according to Objects.equals(Object, Object).
static Predicate isEqual(Object targetRef)
Returns a predicate that tests if two arguments are
equal according to Objects.equals(Object, Object).
T : the type of arguments to the predicate
Parameters:
targetRef : the object reference with which to
compare for equality, which may be null
Returns: a predicate that tests if two arguments
are equal according to Objects.equals(Object, Object)
I can't get a grisp of what this Objects.equals(Object, Object) might be
I write the following code to try it out -
Class Fruits -
Fruits.java -
public class Fruits {
private String fruit;
public Fruits(String fruit) {
this.fruit = fruit;
}
public String getFruit() {
return fruit;
}
}
Here, the other methods of predicate seem to be quite easy to understand -
Predicate<List<Fruits>> containsApple = list -> {
boolean myReturn = false;
Iterator<Fruits> iterator = list.iterator();
while (iterator.hasNext()) {
Fruits fruits = iterator.next();
String fruit = fruits.getFruit();
if (fruit.equals("Apple")) {
myReturn = true;
break;
}
}
return myReturn;
};
Predicate<List<Fruits>> containsOrange = list -> {
boolean myReturn = false;
Iterator<Fruits> iterator = list.iterator();
while (iterator.hasNext()) {
Fruits fruits = iterator.next();
String fruit = fruits.getFruit();
if (fruit.equals("Orange")) {
myReturn = true;
break;
}
}
return myReturn;
};
Predicate<List<Fruits>> containsAppleAndOrange = list -> {
return containsApple.and(containsOrange).test(list);
};
Predicate<List<Fruits>> containsAppleOrRange = list -> {
return containsApple.or(containsOrange).test(list);
};
Predicate<List<Fruits>> notContainsApple = list -> {
return containsApple.negate().test(list);
};
Predicate<List<Fruits>> notContainsOrange = list -> {
return containsOrange.negate().test(list);
};
Predicate<List<Fruits>> notContainsAppleAndOrange = list -> {
return containsAppleAndOrange.negate().test(list);
};
Predicate<List<Fruits>> notContainsAppleOrOrange = list -> {
return containsAppleOrRange.negate().test(list);
};
Here I test it with following data -
List<Fruits> list1 = new ArrayList<>(List.of(
new Fruits("Apple"),
new Fruits("Orange"),
new Fruits("Mango"),
new Fruits("Banana")
));
List<Fruits> list2 = new ArrayList<>(List.of(
new Fruits("Apple"),
new Fruits("Mango"),
new Fruits("Banana"),
new Fruits("Berry")
));
List<Fruits> list3 = new ArrayList<>(List.of(
new Fruits("Orange"),
new Fruits("Mango"),
new Fruits("Banana"),
new Fruits("Berry")
));
Result is as expected.
But in no way can I understand how to implement the isEqual() method -
To see that two arguments are equal are not I create another predicate -
redicate<List<Fruits>> containsApple2 = list -> {
boolean myReturn = false;
Iterator<Fruits> iterator = list.iterator();
while (iterator.hasNext()) {
Fruits fruits = iterator.next();
String fruit = fruits.getFruit();
if (fruit.equals("Apple")) {
myReturn = true;
break;
}
}
return myReturn;
};
I try something like (without understanding why) -
System.out.println(Predicate.isEqual(containsApple).test(list1));
Output - false
Now what happened here?
System.out.println(Predicate.isEqual(containsApple2).test(containsApple));
Output - false
Now again what happened here?
So, how to exactly use this isEqual method?
Predicate.isEqual is a factory method that creates predicates that test if a given thing is equal to the parameter passed in.
Predicate.isEqual(containsApple) creates a Predicate<Predicate<List<Fruits>>> that tests if a given thing is equal to containsApple. However, since containsApple refers to an instance created from a lambda, and nothing much is guaranteed about the equality of instances created from lambda expressions (See the JLS), nothing much can be said about the result of calling test on it. The classes of the lambda instances may or may not implement equals, and containsApple may or may not be the same instance as containsApple2, depending on the implementation.
Rather than comparing lambda instances, a typical example of using Predicate.isEqual is:
Fruits apple = new Fruits("Apple");
Predicate<Fruits> isApple = Predicate.isEqual(apple);
// rather than this slightly longer version:
// Predicate<Fruits> isApple = x -> Objects.equals(x, apple);
Then you can pass isApple around, to other methods that take Predicates, and/or call test on it. isApple.test(apple) would be true, isApple.test(new Fruits("something else")) would be false. I would also recommend that you override equals and hashCode in Fruits.
Note that we generally make predicates that test against individual objects, rather than lists (collections) of things. We would pass these predicates to other methods (such as Stream.filter), and let them do the filtering. For example, to filter a list to get all the apples:
List<Fruits> apples = fruitsList.stream()
.filter(Predicate.isEqual(apple)).toList();
One should use singular here for the class Fruits.
First you must establish equality of Fruit. Also should you ever want it to store in a HashMap or HashSet, a hashCode implementation is important.
public class Fruit {
private final String fruit; // Or name.
public Fruit(String fruit) {
this.fruit = fruit;
}
public String getFruit() {
return fruit;
}
#Override
public boolean equals(Object other) {
return other instanceOf Fruit && ((Fruit) other).fruit.equals(fruit);
}
#Override
public int hashCode() {
return fruit.hashCode();
}
}
The Iterator class is rather old and its primary advantage is you can walk through and still remove an element with iterator.remove(), which is not allowed on the List in a - statefull - for (ConcurrentModificationException).
Predicate<List<Fruit>> containsApple = list -> {
for (Fruit fruit: list) {
if (fruit.getFruit().equals("Apple")) {
return true;
}
}
return false;
};
Predicate<List<Fruit>> containsApple = list -> list.contains(new Fruit("Apple"));
Advisable is to get acquainted with Stream (like for iterating through a collection) and its expressive power.
Predicate<List<Fruit>> containsApple = list ->
list.stream()
.anyMatch(fr -> fr.getFruit().equals("Apple"));
As mentioned by #user16320675 in comments one of the simplest examples would be -
import java.util.function.Predicate;
public class App {
public static void main(String[] args) {
Integer num1 = 2;
Integer num2 = 3;
Predicate<Integer> predicate = Predicate.isEqual(num1);
System.out.println(predicate.test(num1));
System.out.println(predicate.test(num2));
}
}
Output -
true
false
The code can also be rewritten as -
System.out.println(Predicate.isEqual(num1).test(num1));
System.out.println(Predicate.isEqual(num1).test(num2));
with same output.
A practical application in Java streams -
Code -
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
public class App {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Elephant");
list.add("Hippo");
list.add("Rhino");
list.add("Deer");
list.add("Hippo");
list.add("Zebra");
Predicate<String> predicate = Predicate.isEqual("Hippo");
list.stream().filter(predicate).forEach(System.out::println);
}
}
Output -
Hippo
Hippo

Java sort array of objects by integer field and if those are identical then sort by another integer value

I have a java problem in relation too sorting an arrayList of objects.
I have already figured out to sort an arrayList of object by specific fields, which can be seen in the following code
public void printPrioritized() {
System.out.println("Prioritized todo:");
System.out.println("-----------------");
List<Task> sortedList = new ArrayList<Task>(taskList);
Collections.sort(sortedList, new Comparator<Task>() {
public int compare(Task o1, Task o2) {
return Integer.valueOf(o1.getPriority()).compareTo(o2.getPriority());
}
});
sortedList.forEach((e) -> {
System.out.println(e);
});
My problem is that if to object fields are the same then i am supposed to sort by another value. This means that i have to sort by an value of 1 to 4 (getPriority() method), but if two objects for instance both are 2 then i have to sort by another value which for instance could be time. Hope someone can help.
Assuming your Task class looks something like:
class Task {
int priority;
int anotherValue;
// getters, setters ...
}
you can create custom compartors and chain them while sorting, example:
List<Task> myList = new ArrayList<>();
Comparator<Task> byPriority = (t1,t2) -> Integer.compare(t1.getPriority(), t2.getPriority());
Comparator<Task> byAnotherValue = (t1,t2) -> Integer.compare(t1.getAnotherValue(), t2.getAnotherValue());
myList.sort(byPriority.thenComparing(byAnotherValue));
OR
you can combine those sortings ->
List<Task> myList = new ArrayList<>();
Comparator<Task> sortedComparator = (t1,t2) -> {
if (t1.getPriority() != t2.getPriority()) {
return Integer.compare(t1.getPriority(), t2.getPriority());
}
else if (t1.getAnotherValue() != t2.getAnotherValue()) {
return Integer.compare(t1.getAnotherValue(), t2.getAnotherValue());
}
};
myList.sort(sortedComparator);
Try to customize the compare method.
e.g.
if(o1.getPriority() != o2.getPriority())
return Integer.valueOf(o1.getPriority()).compareTo(o2.getPriority());
if(o1.getTime() != o2.getTime())
return Integer.valueOf(o1.getTime()).compareTo(o2.getTime());
return 0; //they are equal with all fields

Compare two Lists and same values store in third List issue

Hy, I am having trouble with comparing two list. The goal is to compare two lists, find the same values and store those values into third list. What I have found till yet is just the way to return boolean value, but no way to return list value.. any ideas?
here are my two methods for getting values from database:
#Override
public List<BrojPolice> dohvatiBrojPolice() {
List<BrojPolice> filter = jdbcTemplate.query("SELECT*FROM ins2.kalk_cpi;",new Object[]{},
(rs,rowNum) ->{
BrojPolice bp = new BrojPolice();
bp.setBroj(rs.getString("BROJ_POLICE"));
return bp;
});
return filter;
}
#Override
public List<BrojPolice> dohvatiBrojPolice2() {
List<BrojPolice> filter2 = jdbcTemplate.query("SELECT*FROM ins_RAZNO.ADND_DATOTEKA;",new Object[]{},
(rs,rowNum) ->{
BrojPolice bp = new BrojPolice();
bp.setBroj(rs.getString("BROJ_POLICE"));
return bp;
});
return filter2;
}
public List<String> brojPolice(){
boolean match = dohvatiBrojPolice().contains(dohvatiBrojPolice2());
//ideas?
return //List
}
Instead of handling this in code you could write an SQL statement that gives the desired result
SELECT
BROJ_POLICE
FROM
ins2.kalk_cpi AS a
INNER JOIN
ins_RAZNO.ADND_DATOTEKA AS b
ON
a.BROJ_POLICE = b.BROJ_POLICE
That way you waste less memory on getting 2 possibly huge lists with only some common values.
// QUERY = query from above, omitted for readability
List<BrojPolice> list = jdbcTemplate.query(QUERY, new Object[0],
(rs,rowNum) -> {
BrojPolice bp = new BrojPolice();
bp.setBroj(rs.getString("BROJ_POLICE"));
return bp;
});
How to do it in java:
List<A> a = list1();
List<A> b = list2();
// A has to implement equals and hashCode
List<A> result = new ArrayList<A>();
for (A element : a) {
if (b.contains(element)) // this requires a proper equals implementations
result.add(element);
}
return result;
Note that doing list1.contains(list2) would always be false in this case because contains checks whether the element is contained.
You can use List.retainAll as :
List<BrojPolice> common = new ArrayList<>(dohvatiBrojPolice());
common.retainAll(dohvatiBrojPolice2());
This would require the BrojPolice to be comparable with proper hashCode and equals.
If you're looking for a stream or forEach solution for this
List<BrojPolice> common = dohvatiBrojPolice().stream()
.filter(a -> dohvatiBrojPolice2().contains(a))
.collect(Collectors.toList());
First your BrojPolice class needs to have hashCode and equals method implemented so that contains method works as expected. Try below method then:
public List<BrojPolice> intersection(List< BrojPolice > list1, List<BrojPolice> list2) {
List<BrojPolice> intersection = new ArrayList<BrojPolice>();
for (BrojPolice bp : list1) {
if(list2.contains(bp)) {
list.add(bp);
}
}
return intersection;
}

remove an element from list object [duplicate]

This question already has answers here:
How do I remove an object from an ArrayList in Java?
(9 answers)
Closed 5 years ago.
I have a List object which holds 10 elements, i have to do conditional check and remove some of the elements from the list. I have done as below, but it is not working as expected, any inputs?
List<MyDTO> myList = new ArrayList<MyDTO>(); //myist.size () is 10
I want to check as below:
for(MyDTO res : myList){
if(res.getResult().equals("cancel")){
myList.remove()
}
}
As shown in above code, if res.getResult() is "cancel" i want to remove that particular object from the list(myList). Is it the correct way to remove an element completely from list based on conditional check?
Simply use removeIf on your list, for example if you had list of Integers ranging from 1 to 10 and you wanted to remove Integers larger than 4, you would do:
yourListHere.removeIf(x -> x > 4);
Resulting list would contain: 1, 2, 3 and 4
Read here about removeIf:
https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html#removeIf-java.util.function.Predicate-
BONUS
Additional resources if you are unfamiliar with Java 8 features:
Lambdas - https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html
Functional Interfaces - https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html
Use removeIf:
default boolean removeIf(Predicate<? super E> filter)
Removes all of the elements of this collection that satisfy the given
predicate. Errors or runtime exceptions thrown during iteration or by
the predicate are relayed to the caller.
In your example:
myList.removeIf(res -> res.getResult().equals("cancel"));
As an alternative to removeIf you can use the Java stream solution:
List<MyDTO> newList = myList.stream()
.filter(s -> !s.getResult().equals("cancel"))
.collect(Collectors.toList());
This might be more convenient when the length of the input list and the number of elements to remove is relatively large.
If use Java 8:
myList.removeIf(x -> x.getResult().equals("cancel"));
If older (6,7):
public class MyDTO {
private String result;
(...)
public MyDTO(String result) {
this.result = result;
}
public String getResult() {
return result;
}
(...)
#Override
public int hashCode() {
return 31;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final MyDTO other = (MyDTO) obj;
return !((this.result == null) ? (other.result != null) : !this.result.equals(other.result));
}
(...)
}
then:
MyDTO toRemove = new MyDTO("cancel");
while(myList.contains(toRemove))
myList.remove(toRemove);
or:
List<MyDTO> toRemove = new ArrayList<MyDTO>();
for(MyDTO res : myList){
if(res.getResult().equals("cancel")){
toRemove.add(res);
}
}
myList.removeAll(toRemove);
Without overriding the equals method:
for(int i = 0; i < myList.size() ; i++)
if(myList.get(i).getResult().equals("cancel"))
myList.remove(i);
or:
Iterator<MyDTO> i = myList.iterator();
while (i.hasNext())
if(i.next().getResult().equals("cancel"))
i.remove();

.equal doesn't work for list of list even if they are equal [duplicate]

This question already has answers here:
How to compare two maps by their values
(13 answers)
Closed 6 years ago.
So when I am checking freqMap1.values() and freqMap2.values() have the same values but when I check it with .equals it returns false. I am baffled as to how fix this problem:
/**
* Created by mona on 5/26/16.
*/
import java.util.*;
public class IsomorphicStrings {
//the words "abca" and "zbxz" are isomorphic
public static boolean areIsomorphic(String s1, String s2) {
Map<Character, ArrayList<Integer>> freqMap1 = new LinkedHashMap<>();
Map<Character, ArrayList<Integer>> freqMap2 = new LinkedHashMap<>();
for (int i=0; i<s1.length(); i++) {
if (freqMap1.containsKey(s1.charAt(i))) {
freqMap1.get(s1.charAt(i)).add(i);
} else {
freqMap1.put(s1.charAt(i), new ArrayList<>(Arrays.asList(i)));
}
}
for (int i=0; i<s2.length(); i++) {
if (freqMap2.containsKey(s2.charAt(i))) {
freqMap2.get(s2.charAt(i)).add(i);
} else {
freqMap2.put(s2.charAt(i), new ArrayList<>(Arrays.asList(i)));
}
}
System.out.println(freqMap1.values());
System.out.println(freqMap2.values());
return freqMap1.values().equals(freqMap2.values());
}
public static void main(String[] args) {
String s1="foo";
String s2="app";
System.out.println(areIsomorphic(s1, s2));
}
}
This is the output I get from prints:
[[0], [1, 2]]
[[0], [1, 2]]
false
values() returns a Collection implementation that doesn't override Object's equals. Therefore, you are comparing object references instead of the contents of the Collections.
You can compare them by converting these Collections to Lists before calling equals :
new ArrayList<ArrayList<Integer>>(freqMap1.values()).equals(new ArrayList<ArrayList<Integer>>freqMap2.values()))
This will return true only if both values() Collections contain the same elements in the same iteration order. If you don't care about the order and about duplicate values, you can convert the values() Collections to HashSet instead of ArrayList. Now you'll get true if both values() Collections contain the same unique elements, regardless of iteration order.
In Java 7+, the following would work:
return new ArrayList<>(freqMap1.values()).equals(new ArrayList<>(freqMap2.values()));
I think the problem might be that you are comparing List of List with equals. The following solves the problem for me.
List<ArrayList<Integer>> map1Values = new ArrayList(freqMap1.values());
List<ArrayList<Integer>> map2Values = new ArrayList(freqMap2.values());
if(map1Values.get(i).size() != map2Values.get(i)){
return false;
}
boolean result = true;
for(int i=0;i<map1Values.size() && result;i++){
boolean tmp = Objects.equals(map1Values.get(i), map2Values.get(i));
result = result && tmp;
}
return result;

Categories

Resources