我有一个扁平的多地图(列表)对象,我想将其转换为一个列表,其中'key'属性/字段(例如下面的 name )在所有条目中都是唯一的。
如果多个条目具有相同的密钥(名称),则应选择具有最大 creationDate 字段的条目。
示例:
List<Object> myList =
[
{name="abc", age=23, creationDate = 1234L},
{name="abc", age=12, creationDate = 2345L},
{name="ddd", age=99, creationDate = 9999L}
]
应转换为:
List<Object> =
[
{name="abc", age=12, creationDate = 2345L},
{name="ddd", age=99, creationDate = 9999L}
]
是否有一种优雅的方式(可能使用Guava库?)在Java中解决这个问题?我意识到我可以尝试使用带有 name 的HashMap作为查找所有唯一条目的键,但我觉得有更好的方法可以解决这个问题。
谢谢!
答案 0 :(得分:3)
如果您有可能使用Java 8,我会推荐Streams,因为已经告知了其他答案。 如果没有,你可以选择这样的东西。
首先,您通过creationDate对List desending进行排序。然后,您创建一个TreeSet,将所有具有相同名称的人视为相等。因此,只会添加第一个(最高的)creationDate,而忽略其他的。
List<Person> persons = new ArrayList<>();
persons.add(new Person("abc", 23, 1234L));
persons.add(new Person("abc", 12, 2345L));
persons.add(new Person("def", 99, 9999L));
Collections.sort(persons, new Comparator<Person>() {
public int compare(Person o1, Person o2) {
return (int) (o2.creationDate - o1.creationDate);
}
});
Set<Person> personsHashed = new TreeSet<>(new Comparator<Person>() {
public int compare(Person o1, Person o2) {
return o2.name.compareTo(o1.name);
}
});
personsHashed.addAll(persons);
答案 1 :(得分:2)
这是否被认为是优雅的是相当主观的,但这里是:
static List<Person> byName(Collection<Person> persons) {
Map<String, Person> personsByName = persons.stream().collect(
Collectors.groupingBy(Person::getName,
Collectors.collectingAndThen(
Collectors.maxBy(
Comparator.comparingLong(Person::getCreationDate)),
p -> p.get())));
return new ArrayList<Person>(personsByName.values());
}
通过对收集器和比较器的方法使用静态导入,可以使其更具可读性,例如:
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.maxBy;
import static java.util.Comparator.comparingLong;
然后代码可以略微缩短为:
static List<Person> byName(Collection<Person> persons) {
Map<String, Person> personsByName =
persons.stream().collect(
groupingBy(Person::getName, collectingAndThen(
maxBy(comparingLong(Person::getCreationDate)),
p -> p.get())));
return new ArrayList<Person>(personsByName.values());
}
答案 2 :(得分:1)
在Java 8中,您可以使用新的Streaming API将集合Stream通过过滤器,然后生成结果。那应该能够做你想要的。
或者,您已考虑将它们放入HashMap的想法看起来非常简单,并且会提供您需要的行为。我不会试着过度思考这个:)