【问题标题】:Collecting a collection of list based on similar index收集基于相似索引的列表集合
【发布时间】:2019-07-06 03:16:38
【问题描述】:

我有一个像这样的集合: List<List<Object>> firstList

我想将一个类似的模式列表组合在一起: List<List<Object>> secondList 但按索引分组。

firstList [1]:
   0 = {Object A}"
   1 = {Object B}"
   2 = {Object C}"

firstList [2]:
   0 = {Object A}"
   1 = {Object B}"
   2 = {Object C}"

我想将此集合分组为

secondList [1]:
   0 = {Object A}"
   1 = {Object A}"

secondList [2]:
   0 = {Object B}"
   1 = {Object B}"

secondList [3]:
   0 = {Object C}"
   1 = {Object C}"

到目前为止我尝试过的是

for (int i = 0; i <firstList.size() ; i++) {
    List<Object> list = firstList.get(i);
    List<Object> rlPr = new ArrayList<>();

    for (int j = 0; j <list.size()-1; j++) {
        rlPr.add(list.get(i));
    }
    secondList.add(rlPr);
}

但我没有得到预期的结果。 我正在使用 java 8。

编辑:所有列表的大小都相同

【问题讨论】:

  • @michael 正确。那是一个错字。我已经更正了。谢谢!
  • 尝试使用具有索引作为键的Map&lt;Integer, List&lt;Object&gt;&gt;,并在解析源列表后从地图中获取值
  • 所以你不想“按索引分组”,而是按项目分组?您似乎正在丢弃原始索引,并多次维护同一个对象。

标签: java loops collections java-8 iteration


【解决方案1】:

您可以使用Map 按索引对值进行分组:

Map<Integer, List<Object>> map = new TreeMap<>();
for (List<Object> objects : firstList) {
    for (int i = 0, l = objects.size(); i < l; i++) {
        map.computeIfAbsent(i, k -> new ArrayList<>()).add(objects.get(i));
    }
}

然后返回List

List<List<Object>> secondList = new ArrayList<>(map.values());

【讨论】:

  • 最简洁优雅的解决方案,也是最具表现力的解决方案。如果可能的话,我会多次投票
  • @FedericoPeraltaSchaffner 谢谢。我自己并不认为这会是一件容易的事,我真的认为它会包含更多的复杂性:)
  • 正如其他 cmets 中提到的,最优雅的解决方案。谢谢@Lino。
  • int i = 0, l = objects.size(); i &lt; l 为什么不只是int i = 0; i &lt; objects.size()
  • @Lino 我不这么认为。您已经牺牲了可读性,根本没有明显的性能优势。如果你关心方法调用,你应该在循环之前初始化变量,给它一个有意义的名字,比如length,然后让它成为final。对任何有效的最终变量使用循环初始化程序都是误用,因为当我阅读它时,我需要扫描整个循环体以确保您没有更改它。
【解决方案2】:

首先,获取子列表的最大长度。在您的情况下,两者都是 3。遍历所有这些索引,从该索引的每个子列表中获取值并将这些值收集到一个新的子列表中。

final int maxLengthOfSublist = list1.stream().mapToInt(List::size).max().orElse(0);
final List<List<Integer>> list2 = IntStream.range(0, maxLengthOfSublist)
    .mapToObj(idx -> list1.stream()
        .filter(sublist -> idx < sublist.size())
        .map(sublist -> sublist.get(idx))
        .collect(Collectors.toList())
    )
    .collect(Collectors.toList());

即使子列表的长度不同,这也会起作用。

【讨论】:

  • 不同大小列表的通用解决方案
【解决方案3】:

假设主列表中的列表大小相同,您可以执行以下操作...

    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.List;

    public class OhCrikey {

        public static void main(String[] args) {
            List<List<String>> lists = Arrays.asList(
                    Arrays.asList("1a", "2a", "3a"),
                    Arrays.asList("1b", "2b", "3b"),
                    Arrays.asList("1c", "2c", "3c")
            );

            List<List<String>> result = transform(lists);

            result.forEach(System.out::println);
        }

        private static <T> List<List<T>> transform(List<List<T>> lists) {
            if(lists == null || lists.isEmpty()) {
                return Collections.emptyList();
            }
            // Check each sub-list contains the same number of elements
            checkAllSameSize(lists);

            // Initialise the results list
            List<List<T>> result = new ArrayList<>();

            // Get the size of each sub-list
            int totalLists = lists.get(0).size();

            // Fill up the results list with 'totalLists' empty lists
            for(int k = 0; k < totalLists; k++) {
                result.add(new ArrayList<>());
            }

            // For each input list...
            lists.forEach(list -> {
                // Iterate over it and add the kth element to the kth result list.
                for(int k = 0; k < list.size(); k++) {
                    result.get(k).add(list.get(k));
                }
            });

            return result;
        }

        private static <T> void checkAllSameSize(List<List<T>> lists) {
            int size = lists.get(0).size();

            // Make sure each list has the same size as the first list
            lists.forEach(list -> {
                if(list.size() != size) {
                    throw new AssertionError("All child lists must have same number of elements.");
                }
            });
        }
    }

打印...

    [1a, 1b, 1c]
    [2a, 2b, 2c]
    [3a, 3b, 3c]

【讨论】:

  • 按预期工作。但是使用的逻辑相当大。相对而言,Lino 的回答似乎有点紧凑。
【解决方案4】:

一种流式处理方式是(将Object 替换为CustomObject):

List<List<CustomObject>> secondList = new ArrayList<>( // Collection to ArrayList
       firstList.stream() // Stream<List<CustomObject>>
                .flatMap(Collection::stream) // Stream<CustomObject>
                .collect(Collectors.groupingBy(Function.identity())) // Map<CustomObject, List<CustomObject>>
                .values()); // Collection<List<CustomObject>>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-12
    • 1970-01-01
    • 1970-01-01
    • 2022-08-19
    • 1970-01-01
    • 1970-01-01
    • 2021-03-11
    相关资源
    最近更新 更多