代码之家  ›  专栏  ›  技术社区  ›  lapots

用对键将三元组列表组合成映射

  •  1
  • lapots  · 技术社区  · 6 年前

    我有一张清单 triples

    List<Triple<String, String, String>> triplets; 
    

    我想把它们组合成这样的地图

    Map<Pair<String, String>, String> mapping;
    

    在哪里? value 地图的第三个元素是三重元素。如果相同的话 key 它应该覆盖剩余的第三个值。

    例如

    def triples = [ {a, b, c} ; {a, d, e} ; {a, b, f } ]
    // grouping
    def map = [ {a,b} : c ; {a, d} : e ]
    

    如何使用 Java 8 和它的 grouping 在溪流中?

    4 回复  |  直到 6 年前
        1
  •  4
  •   Ravindra Ranwala    6 年前

    这应该可以做到:

    Map<Pair<String, String>, String> result = triplets.stream()
        .collect(
            Collectors.toMap(
                t -> new Pair(t.getOne(), t.getTwo()),
                Triple::getThree,
                (v1, v2) -> v2
            )
        );
    

    部分对类的示例:

    public class Pair<T, U> {
        //...
    
        @Override
        public int hashCode() {
            return one.hashCode() + two.hashCode();
        }
    
        @Override
        public boolean equals(Object obj) {
            if (!(obj instanceof Pair))
                return false;
            Pair p = (Pair) obj;
            return p.one.equals(one) && p.two.equals(two);
        }
    }
    

    这个 HashMap 类用途 equals 方法唯一标识关键对象。所以你首先需要重写 等于 hashcode 方法来显示 Pair 对象 Map 班级。

    然后回到溪流和lambda。每次三联体使用 Collectors.toMap 一对 对象作为键和 Triplet 作为价值。然后提供 mergeFunction 处理键冲突。在您的情况下,您需要保留以前的值,同时丢弃新值。这就是你要做的。

    更新

    我已经按照下面的注释更新了合并函数。

        2
  •  1
  •   tobias_k    6 年前

    如果你想用 Collectors.groupingBy ,可与下游结合 mapping reducing Collectors :

    @Data @AllArgsConstructor
    class Triple {
        String x, y ,z;
    }
    @Data @AllArgsConstructor
    class Pair {
        String x, y;
    }
    
    List<Triple> lst = List.of(new Triple("a", "b", "c"),
                               new Triple("a", "d", "e"),
                               new Triple("a", "b", "f"));
    
    Map<Pair, String> map = lst.stream()
            .collect(Collectors.groupingBy(t -> new Pair(t.x, t.y),
                     Collectors.mapping(t -> t.z, 
                     Collectors.reducing(null, (x,y) -> y))));
    // {Pair(x=a, y=b)=f, Pair(x=a, y=d)=e}
    

    你也可以改变 (x,y) -> y (x,y) -> x 以保持第一次发生。

        3
  •  0
  •   aName    6 年前

    这里ICI是一个可能的解决方案

            String[] l1=new String[]{"a", "b", "c"};
        String[] l2={"a", "d", "e"};
    
        String[] l3={"a", "b", "c"};
        List<String[]> t=new ArrayList<>();
        t.add(l1);
    
        t.add(l2);
        t.add(l3);
    
        Map<String[],String> m=t.stream().
        collect(Collectors.toMap(x->new String[]{x[0],x[1]}, x->x[2],(x,y)->x));
    

    但这取决于 三倍的 如果它覆盖等于,则不会有重复,否则它将在地图的键中重复。

        4
  •  0
  •   Ousmane D.    6 年前

    使用 Map::merge :

    Map<Pair<String, String>, String> result = new HashMap<>();
    triplets.forEach(e -> result.merge(new Pair<>(e.getOne(), e.getThree()), e.getThree(), (o, n) -> o));
    

    这将插入 triplets 列出到一个映射中,其中键是一对,表示 Triple 地图的值是 三倍的 .

    在密钥冲突的情况下,我们使用重新映射函数 (o, n) -> o 维护旧的( o )值。