java 8 如何获取多个属性的不同列表

问题描述 投票:0回答:4

如何从对象列表中获取不同的(基于两个属性的不同)列表。 例如,让有包含属性名称和价格的对象列表。 现在我怎样才能获得具有不同名称或价格的列表。
假设

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

现在让 l1 具有以下属性(名称,价格):-
n1, p1
n1,p2
n2, p1
n2, p3

现在过滤器之后的列表应该是-
n1, p1
n2,p3

我尝试像这样解决-

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

现在的问题是,当我过滤名称时,列表返回将是 -
n1, p1
n2, p1

然后它会对返回的价格运行过滤器 -
n1, p1

这不是预期的结果。

java lambda java-8 java-stream distinct-values
4个回答
9
投票

几乎逐字逐句来自Stuart Marks 的回答

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

这个主要方法产生:

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

编辑

按照尤金的提示,将价格定为

int

注意:如果你想充实它,你可以使用更有趣的东西作为键:

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

6
投票

我会选择这样的东西,它相当简单且灵活,并且基于您的示例:

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;

    };

}

然后可以通过以下方式调用:

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

2
投票

这是我基于类

Item
的解决方案,它定义了
name
price
:

public class Item {

    public String name;
    public double price;

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

要求是从给定的

Item
中仅获取具有不同
List<Item>
不同
nameprice
,按照它们出现的顺序。

我明白了按类别区分的要求

ItemWrapper

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

现在我们已准备好过滤给定

List<Item>

 的项目:

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

如下:

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

捕获的物品有:

    名称=名称-1,价格=100.0
  • 名称=名称-2,价格=999.99
  • 名称=名称-4,价格=555.0

0
投票
为什么不那样呢:

@Value static class User { String firstName; String lastName; int age; } public static void main(String[] args) { var user1 = new User("firstName1", "lastName1", 20); var user2 = new User("firstName1", "lastName2", 20); var user3 = new User("firstName3", "lastName3", 30); var users = List.of(user1, user2, user3); var uniqueByFirstNameAndAge = users .stream() .collect(Collectors.toMap(usr -> Set.of(usr.getFirstName(), usr.getAge()), Function.identity(), (usr1, usr2) -> usr1)) .values(); System.out.println(uniqueByFirstNameAndAge); }
    
© www.soinside.com 2019 - 2024. All rights reserved.