Java 8 how to get a separate list for several properties

How can I get a separate (defined based on two properties) list from a list of objects. for example, let a list of objects with a name and price. Now, how can I get a list with a great name or price.
Let's pretend that

list<xyz> l1 = getlist(); // getlist will return the list. 

Now let l1 have the following properties (name, price): -
n1, p1
n1, p2
n2, p1
n2, p3

Now, after the filter, the list should be n1, p1
n2, p3

I tried to solve like this -

 public List<xyz> getFilteredList(List<xyz> l1) { return l1 .stream() .filter(distinctByKey(xyz::getName)) .filter(distinctByKey(xyz::getPrice)) .collect(Collectors.toList()); } private static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) { Map<Object,Boolean> seen = new ConcurrentHashMap<>(); return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null; } 

Now the problem is that when I made a filter by name, the list will be returned -
n1, p1
n2, p1

and then it will run the filter at a price that returns -
n1, p1

which is not the expected result.

+6
source share
3 answers

Almost verbatim from Stuart Marx 's answer :

 import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; class Class { public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) { Map<Object, Boolean> seen = new ConcurrentHashMap<>(); return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null; } private static List<Pojo> getList() { return Arrays.asList( new Pojo("123", 100), new Pojo("123", 100), new Pojo("123", 100), new Pojo("456", 200) ); } public static void main(String[] args) { System.out.println(getList().stream() // extract a key for each Pojo in here. // concatenating name and price together works as an example .filter(distinctByKey(p -> p.getName() + p.getPrice())) .collect(Collectors.toList())); } } class Pojo { private final String name; private final Integer price; public Pojo(final String name, final Integer price) { this.name = name; this.price = price; } public String getName() { return name; } public Integer getPrice() { return price; } @Override public String toString() { final StringBuilder sb = new StringBuilder("Pojo{"); sb.append("name='").append(name).append('\''); sb.append(", price=").append(price); sb.append('}'); return sb.toString(); } } 

This basic method gives:

[Pojo {name = '123', price = 100}, Pojo {name = '456', price = 200}]

Edit

The price a int for the Eugene tooltip.

Please note: that you could use something more interesting as a key if you would like to implement it:

 import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; class Class { public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) { Map<Object, Boolean> seen = new ConcurrentHashMap<>(); return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null; } private static List<Pojo> getList() { return Arrays.asList( new Pojo("123", 100), new Pojo("123", 100), new Pojo("123", 100), new Pojo("456", 200) ); } private static class NameAndPricePojoKey { final String name; final int price; public NameAndPricePojoKey(final Pojo pojo) { this.name = pojo.getName(); this.price = pojo.getPrice(); } @Override public boolean equals(final Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; final NameAndPricePojoKey that = (NameAndPricePojoKey) o; if (price != that.price) return false; return name != null ? name.equals(that.name) : that.name == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + price; return result; } } public static void main(String[] args) { System.out.println(getList().stream() // extract a key for each Pojo in here. .filter(distinctByKey(NameAndPricePojoKey::new)) .collect(Collectors.toList())); } } class Pojo { private String name; private Integer price; private Object otherField1; private Object otherField2; public Pojo(final String name, final Integer price) { this.name = name; this.price = price; } public String getName() { return name; } public void setName(final String name) { this.name = name; } public Integer getPrice() { return price; } public void setPrice(final Integer price) { this.price = price; } public Object getOtherField1() { return otherField1; } public void setOtherField1(final Object otherField1) { this.otherField1 = otherField1; } public Object getOtherField2() { return otherField2; } public void setOtherField2(final Object otherField2) { this.otherField2 = otherField2; } @Override public boolean equals(final Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; final Pojo pojo = (Pojo) o; if (name != null ? !name.equals(pojo.name) : pojo.name != null) return false; if (price != null ? !price.equals(pojo.price) : pojo.price != null) return false; if (otherField1 != null ? !otherField1.equals(pojo.otherField1) : pojo.otherField1 != null) return false; return otherField2 != null ? otherField2.equals(pojo.otherField2) : pojo.otherField2 == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + (price != null ? price.hashCode() : 0); result = 31 * result + (otherField1 != null ? otherField1.hashCode() : 0); result = 31 * result + (otherField2 != null ? otherField2.hashCode() : 0); return result; } @Override public String toString() { final StringBuilder sb = new StringBuilder("Pojo{"); sb.append("name='").append(name).append('\''); sb.append(", price=").append(price); sb.append(", otherField1=").append(otherField1); sb.append(", otherField2=").append(otherField2); sb.append('}'); return sb.toString(); } } 
+3
source

Here is my solution based on the Item class that defines name and a price :

 public class Item { public String name; public double price; Item(String name, double price) { this.name = name; this.price = price; } } 

The requirement is to get only Item from a given List<Item> , which have different name and different price s, in the order in which they occur.

I catch this requirement to be different from the ItemWrapper class:

 public class ItemWrapper { Item item; ItemWrapper(Item item) { this.item = item; } @Override public boolean equals(Object obj) { if (!(obj instanceof ItemWrapper)) return false; ItemWrapper other = (ItemWrapper) obj; return Objects.equals(item.name, other.item.name) || item.price == other.item.price; } @Override public int hashCode() { return 1; } } 

Now we have everything to filter the given List<Item> elements:

 List<Item> items = Arrays.asList( new Item("name-1", 100.00), new Item("name-1", 555.00), new Item("name-2", 100.00), new Item("name-2", 999.99), new Item("name-3", 100.00), new Item("name-4", 555.00), new Item("name-5", 999.99) ); 

in the following way:

 items.stream() .map(item -> new ItemWrapper(item)) .distinct() .map(wrapper -> wrapper.item) .collect(Collectors.toList()); } 

Selected Items:

  • name = name-1, price = 100.0
  • name = name-2, price = 999.99
  • name = name-4, price = 555.0
+2
source

I would go for something like this, which is pretty simple and flexible, and is based on your example:

 public static <T> List<T> distinctList(List<T> list, Function<? super T, ?>... keyExtractors) { return list .stream() .filter(distinctByKeys(keyExtractors)) .collect(Collectors.toList()); } private static <T> Predicate<T> distinctByKeys(Function<? super T, ?>... keyExtractors) { final Map<List<?>, Boolean> seen = new ConcurrentHashMap<>(); return t -> { final List<?> keys = Arrays.stream(keyExtractors) .map(ke -> ke.apply(t)) .collect(Collectors.toList()); return seen.putIfAbsent(keys, Boolean.TRUE) == null; }; } 

Then it can be called as follows:

 final List<Xyz> distinct = distinctList(list, Xyz::getName, Xyz::getPrice) 
+1
source

Source: https://habr.com/ru/post/1265507/


All Articles