Create/Sort 列表<X> 值的排序与列表<Y> 中的相同
Create/Sort List<X> with values ordered the same as in List<Y>
我有一个对象列表 A
,用于检索另一个对象列表 B
。但是第二个列表是随机排序的。两种对象类型都有 id
属性 的共同点。
我现在在做什么:
List<A> input = ...;
List<B> output = new ArrayList<>();
for(A a : input) {
output.add(getOutputObjectById(a.getId()));
}
问题是,getOutputObjectById
相当昂贵。还有另一种方法 getOutputObjectsByIds
需要 Collection
个 id 和 returns List<B>
。 但是元素的顺序可以不同。虽然我需要一种方法来确保两个列表最后的排序相同。
我首先想到使用 LinkedHashMap
并执行如下操作:
List<A> input = ...;
List<B> output = new ArrayList<>();
LinkedHashMap<String, Object> intermediate = new LinkedHashMap<String, Object>();
for(A a : input) {
intermediate.put(a.getId(), a);
}
for(B b : getOutputObjectsByIds(intermediate.keySet())) {
intermediate.put(b.getId(), b);
}
for(Object o : intermediate.values()) {
output.add((B) o);
}
这么多代码,在多个集合中复制对象等等
我真的希望,有一个更短、更优雅的方法来做到这一点。
你有什么想法吗?
看起来你标记了这个 java-8
所以我将提供流的使用:
List<A> input = ...;
HashMap<IdClass, B> bsById = new HashMap<>();
for(B b : getOutputObjectsByIds(input.stream().map(A::getId).collect(Collectors.toList()))){
bsById.put(b.getId(), b);
}
return input.stream().map((A a)->bsById.get(a.getId())).collect(Collectors.toList());
这使用中间 HashMap
,以避免对 input
的每个成员的列表进行并行扫描的 O(n^2) 情况。
基于 hexafraction 的工作,我创建了一个非常相似的解决方案,它不会创建新的 List
,而是对给定的 List
:
进行排序
/*
* converts a Collection<T> to Map<ID, T>
* ID is specified by the keyFunction
*/
public static <T, ID> Map<ID, T> collectionToMap(Collection<T> collection, Function<T, ID> keyFunction) {
return collection.stream().collect(Collectors.toMap(keyFunction, Function.identity()));
}
/*
* sorts List<T> to have the same ordering as List<O>
* two functions have to be provided, that are used to get the List's ID
*/
public static <T, O, ID> void sortListByObjects(List<T> list, Function<T, ID> listIdFunction, List<O> objects, Function<O, ID> objectIdFunction) {
Map<ID, T> map = collectionToMap(list, listIdFunction);
for(int i = 0; i < objects.size(); i++) {
list.set(i, map.get(objectIdFunction.apply(objects.get(i))));
}
}
/*
* abstraction of the method above, which sorts List<T> by a List of IDs
*/
public static <T, ID> void sortListByIds(List<T> list, Function<T, ID> listIdFunction, List<ID> ids) {
sortListByObjects(list, listIdFunction, ids, Function.identity());
}
使用起来非常简单:
List<String> ids = Arrays.asList("4", "1", "9");
List<Foo> unsortedList = Arrays.asList(new Foo("1"), new Foo("9"), new Foo("4"));
sortListByIds(unsortedList, foo -> foo.getId(), ids);
或者:
List<Foo> unsortedList = Arrays.asList(new Foo("1"), new Foo("9"), new Foo("4"));
List<Bar> sortedList = Arrays.asList(new Bar("4"), new Bar("1"), new Bar("4"));
sortListByObjects(unsortedList, foo -> foo.getId(), sortedList, bar -> bar.getId());
我有一个对象列表 A
,用于检索另一个对象列表 B
。但是第二个列表是随机排序的。两种对象类型都有 id
属性 的共同点。
我现在在做什么:
List<A> input = ...;
List<B> output = new ArrayList<>();
for(A a : input) {
output.add(getOutputObjectById(a.getId()));
}
问题是,getOutputObjectById
相当昂贵。还有另一种方法 getOutputObjectsByIds
需要 Collection
个 id 和 returns List<B>
。 但是元素的顺序可以不同。虽然我需要一种方法来确保两个列表最后的排序相同。
我首先想到使用 LinkedHashMap
并执行如下操作:
List<A> input = ...;
List<B> output = new ArrayList<>();
LinkedHashMap<String, Object> intermediate = new LinkedHashMap<String, Object>();
for(A a : input) {
intermediate.put(a.getId(), a);
}
for(B b : getOutputObjectsByIds(intermediate.keySet())) {
intermediate.put(b.getId(), b);
}
for(Object o : intermediate.values()) {
output.add((B) o);
}
这么多代码,在多个集合中复制对象等等
我真的希望,有一个更短、更优雅的方法来做到这一点。
你有什么想法吗?
看起来你标记了这个 java-8
所以我将提供流的使用:
List<A> input = ...;
HashMap<IdClass, B> bsById = new HashMap<>();
for(B b : getOutputObjectsByIds(input.stream().map(A::getId).collect(Collectors.toList()))){
bsById.put(b.getId(), b);
}
return input.stream().map((A a)->bsById.get(a.getId())).collect(Collectors.toList());
这使用中间 HashMap
,以避免对 input
的每个成员的列表进行并行扫描的 O(n^2) 情况。
基于 hexafraction 的工作,我创建了一个非常相似的解决方案,它不会创建新的 List
,而是对给定的 List
:
/*
* converts a Collection<T> to Map<ID, T>
* ID is specified by the keyFunction
*/
public static <T, ID> Map<ID, T> collectionToMap(Collection<T> collection, Function<T, ID> keyFunction) {
return collection.stream().collect(Collectors.toMap(keyFunction, Function.identity()));
}
/*
* sorts List<T> to have the same ordering as List<O>
* two functions have to be provided, that are used to get the List's ID
*/
public static <T, O, ID> void sortListByObjects(List<T> list, Function<T, ID> listIdFunction, List<O> objects, Function<O, ID> objectIdFunction) {
Map<ID, T> map = collectionToMap(list, listIdFunction);
for(int i = 0; i < objects.size(); i++) {
list.set(i, map.get(objectIdFunction.apply(objects.get(i))));
}
}
/*
* abstraction of the method above, which sorts List<T> by a List of IDs
*/
public static <T, ID> void sortListByIds(List<T> list, Function<T, ID> listIdFunction, List<ID> ids) {
sortListByObjects(list, listIdFunction, ids, Function.identity());
}
使用起来非常简单:
List<String> ids = Arrays.asList("4", "1", "9");
List<Foo> unsortedList = Arrays.asList(new Foo("1"), new Foo("9"), new Foo("4"));
sortListByIds(unsortedList, foo -> foo.getId(), ids);
或者:
List<Foo> unsortedList = Arrays.asList(new Foo("1"), new Foo("9"), new Foo("4"));
List<Bar> sortedList = Arrays.asList(new Bar("4"), new Bar("1"), new Bar("4"));
sortListByObjects(unsortedList, foo -> foo.getId(), sortedList, bar -> bar.getId());