【问题标题】:How to zip two Java Lists如何压缩两个 Java 列表
【发布时间】:2015-11-04 22:47:03
【问题描述】:

我有 2 个列表:

List<String> subjectArr = Arrays.asList<String>("aa", "bb", "cc");
List<Long> numArr = Arrays.asList<Long>(2L, 6L, 4L);

如何创建新的List 并将两个列表压缩到其中?

List<?> subjectNumArr = zip(subjectArr, numArr);
// subjectNumArr == [{'aa',2},{'bb',6},{'cc',4}]

【问题讨论】:

  • 也许,一张地图应该更适合复合收藏
  • 您需要创建一个可用于创建此类列表的自定义对象

标签: java arraylist


【解决方案1】:

这是使用 Pair 类的 Java-8 解决方案(就像在 @ZhekaKozlov 的回答中一样):

public static <A, B> List<Pair<A, B>> zipJava8(List<A> as, List<B> bs) {
    return IntStream.range(0, Math.min(as.size(), bs.size()))
            .mapToObj(i -> new Pair<>(as.get(i), bs.get(i)))
            .collect(Collectors.toList());
}

从 Java 9 开始,您可以使用 Map.entry():

    public static <A, B> List<Map.Entry<A, B>> zipJava8(List<A> as, List<B> bs) {
        return IntStream.range(0, Math.min(as.size(), bs.size()))
                .mapToObj(i -> Map.entry(as.get(i), bs.get(i)))
                .collect(Collectors.toList());
    }

【讨论】:

  • 注意:如果列表不提供有效的随机访问(例如:链表),每个 get() 将是 O(n) 而不是 O(1)
【解决方案2】:

根据related question,您可以使用 Guava (>= 21.0) 来执行此操作:

List<String> subjectArr = Arrays.asList("aa", "bb", "cc");
List<Long> numArr = Arrays.asList(2L, 6L, 4L);
List<Pair> pairs = Streams.zip(subjectArr.stream(), numArr.stream(), Pair::new)
        .collect(Collectors.toList());

请注意,guava 方法被注释为@Beta,虽然这在实践中的含义取决于解释,但该方法自 21.0 版本以来没有改变。

【讨论】:

  • jool,看起来像这样:Seq.of("a","b", "c").zip(Seq.of(3,2,1))
  • 值得注意的是Streams.zip被标记为@Beta,这可能会限制其在某些工作区的使用。
【解决方案3】:

要从Iterator&lt;A&gt;Iterator&lt;B&gt;BiFunction&lt;A, B, C&gt; 中获取Iterator&lt;C&gt;

public static <A, B, C> Iterator<C> map(Iterator<A> a, Iterator<B> b, BiFunction<A, B, C> f) {
    return new Iterator<C>() {
        public boolean hasNext() {
            return a.hasNext() && b.hasNext(); // This uses the shorter of the two `Iterator`s.
        }

        public C next() {
            return f.apply(a.next(), b.next());
        }
    };
}

【讨论】:

    【解决方案4】:

    使用Map.Entry&lt;String, Long&gt; 的ArrayList,检查两个arraylist 的大小是否相等(这似乎是您的要求),如下所示:

    List<Map.Entry<String,Long>> subjectNumArr = new ArrayList<>(numArr.size());
    if (subjectArr.size() == numArr.size()) {
        for (int i = 0; i < subjectArr.size(); ++i) {
            subjectNumArr.add(new AbstractMap.SimpleEntry<String, Long>(subjectArr.get(i), numArr.get(i));
        }   
    }
    

    这就是您需要的所有代码!

    然后,要迭代结果,请使用以下内容:

    for (Map.Entry<String, Long> entry : subjectNumArr) {
        String key = entry.getKey(); 
        Long value = entry.getValue();
    }
    

    或者,您可以通过以下方式简单地获取位置 i 处的对(保持插入顺序):

    Map.Entry<String, Long> entry = subjectNumArr.get(i);
    

    这也可以保存重复的条目,这与我最初建议的 Map 解决方案不同,无需定义您自己的 (Pair) 类。

    【讨论】:

      【解决方案5】:

      你想要的操作叫做zipping

      你需要实现一个方法zip:

      public static <A, B> List<Pair<A, B>> zip(List<A> as, List<B> bs) {
        Iterator<A> it1 = as.iterator();
        Iterator<B> it2 = bs.iterator();
        List<Map.Entry<A, B>> result = new ArrayList<>();
        while (it1.hasNext() && it2.hasNext()) {
          result.add(Map.entry(it1.next(), it2.next()));
        }
        return result;
      }
      

      你可以这样使用它:

      zip(subjectArr, numArr);
      

      【讨论】:

      • 静态工厂方法 makePair&lt;A,B&gt;(A left, B right) 代替 Pair 中的构造函数可以使这一行成为可能:result.add(Pair.makePair(it1.next(), it2.next()));(无需重复类型)
      • @ZhekaKozlov:在这个实现之后我怎样才能访问每个元组的第一个元素?
      • @Silvermoon for (Pair&lt;A, B&gt; pair : list) { pair.left(); } ?
      • @ZhekaKozlov 谢谢,如果我想返回一个浮点元组而不是字符串,应该如何修改 toString 方法?我尝试按照您的建议返回字符串,然后将其转换回浮点数,但它没有用。有什么建议吗?
      【解决方案6】:

      我同意 vefthym 但是如果你必须使用 list 然后创建一个如下所示的类 -:

      class DirtyCoding{
         String subject;
         int numbr;
      }
      

      然后遍历您的列表,创建DirtyCoding 的对象,填充并添加,然后将其添加到List&lt;DirtyCoding&gt;

      【讨论】:

        【解决方案7】:

        我的想法:

        • 为你的配对定义一个类。这使您的代码可扩展(即,如果您想添加第三个字段)。
        • 使用方便的方法Arrays.asList定义您的列表。它易于理解简短并自动生成通用集合。
        • 使用超类或接口作为变量类型。我在示例中使用了List,也许Collection 会更好。如果您需要列表如此具体,请仅将变量声明为 ArrayList。这将使您能够使用其他实现,而无需更改太多代码。

        我会像这样创建Pair 对象:

        import java.util.*;
        
        class Pair {
            String subject;
            Long num;
        }
        
        public class Snippet {
        
            public static void main(String[] args) {
                List<String> subjectArr = Arrays.asList("aa", "bb", "cc");
                List<Long> numArr = Arrays.asList(2l,6l,4l);
        
                // create result list
                List<Pair> pairs = new ArrayList<>();
        
                // determine result size
                int length = Math.min(subjectArr.size(), numArr.size());
        
                // create pairs
                for (int position = 0; position < length; position++) {
                    Pair pair = new Pair();
                    pair.subject = subjectArr.get(position);
                    pair.num = numArr.get(position);
                    pairs.add(pair);
                }
            }
        }
        

        【讨论】:

          【解决方案8】:

          使用Zipping streams using JDK8 with lambda (java.util.stream.Streams.zip) 的答案之一 同时压缩和应用函数

          例如使用压缩流:

          <A,B,C>  Stream<C> zipped(List<A> lista, List<B> listb, BiFunction<A,B,C> zipper){
               int shortestLength = Math.min(lista.size(),listb.size());
               return IntStream.range(0,shortestLength).mapToObject( i -> {
                    return zipper.apply(lista.get(i), listb.get(i));
               });        
          }
          

          你也可以使用 Guava 的 Streams.zip()

          【讨论】:

            【解决方案9】:

            你应该创建一个 List 的 ArrayList:

            ArrayList<List> subjectNumArr = new ArrayList<>();
            Iterator iter = subjectArr.iterator();
            int count=0;
            while(iter.hasNext()){
                subjectNumArr.add(Arrays.asList(iter.next(),numArr.get[count++]);
            }
            

            【讨论】:

              【解决方案10】:

              在 Java 8 中: 您可以使用 Stream 和 Collectors 类在一行中完成此操作。

              在 Java 7/6/5 中:

              List list = new ArrayList();
              
                      if(subjectArr.size() == numArr.size())
                      {
                          for (int i = 0; i < subjectArr.size(); i++) { // Loop through every subject/name
                              list.add(subjectArr.get(i) + " " + numArr.get(i)); // Concat the two, and add it
                          }
                      }
              

              【讨论】:

              • 你将如何在 Java8 中做到这一点?
              猜你喜欢
              • 2011-11-20
              • 2019-06-16
              • 1970-01-01
              • 1970-01-01
              • 2013-11-10
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多