流分组:减少到列表的第一个元素

时间:2015-12-28 15:00:02

标签: java java-8 grouping java-stream collectors

我有一个List<Valuta>可以表示(简化)JSON风格:

  

[{codice = EUR,description = Euro,ratio = 1},{codice = USD,   description =美元,比率= 1.1}]

我想在Map<String, Valuta>这样转换它:

  

{EUR = {codice = EUR,description = Euro,ratio = 1},USD = {codice = USD,   description =美元,比率= 1.1}}

我写了这个单行:

getValute().stream().collect(Collectors.groupingBy(Valuta::getCodice));

但这会返回Map<String, List<Valuta>>而不是我需要的内容。

我认为mapping()函数对我有用,但不知道如何。

6 个答案:

答案 0 :(得分:31)

实际上,您需要在此使用Collectors.groupingBy而不是Map<String, Valuta> map = getValute().stream() .collect(Collectors.toMap(Valuta::getCodice, Function.identity()));

List

groupingBy用于根据分组功能对Stream的元素进行分组。 2默认情况下,与分组功能具有相同结果的流元素将被收集到Map

toMap会将元素收集到toMap中,其中键是应用给定键映射器的结果,值是应用值映射器的结果。请注意,默认情况下,如果遇到重复,coord_polar()将抛出异常。

答案 1 :(得分:11)

您可以使用Collectors.toMap(keyMappingFunction, valueMappingFunction)

Map<String, Valuta> map = list
        .stream()
        .collect(Collectors.toMap(Valuta::getCodice, v -> v));

如果您发现v->v更具可读性,则可以将Function.identity()替换为Collectors.toMap

答案 2 :(得分:11)

游戏有点晚了,但试试这个:

Map<String, Valuta> map = 
    getValute().stream()
               .collect(Collectors.groupingBy(Valuta::getCodice,
                            Collectors.collectingAndThen(
                                Collectors.toList(), 
                                values -> values.get(0))));

答案 3 :(得分:4)

在冲突时选择第一个值而不抛出异常的toMap版本是:

Collectors.toMap(keyMapper, valueMapper, mergeFunction)

Map<String, Valuta> map = list
        .stream()
        .collect(Collectors.toMap(Valuta::getCodice, v -> v, (v1, v2) -> v1));

答案 4 :(得分:0)

这里有3种方法。

public class Test1 {
  static class Foo {
    public int id, targetCost, actualCost;
    public String ref;

    public Foo(int id, String ref, int actualCost, int targetCost) {

      this.id = id;
      this.targetCost = targetCost;
      this.actualCost = actualCost;
      this.ref = ref;
    }

    public int getId() {
      return id;
    }

    public void setId(int id) {
      this.id = id;
    }

    public int getTargetCost() {
      return targetCost;
    }

    public void setTargetCost(int targetCost) {
      this.targetCost = targetCost;
    }

    public int getActualCost() {
      return actualCost;
    }

    public void setActualCost(int actualCost) {
      this.actualCost = actualCost;
    }

    public String getRef() {
      return ref;
    }

    public void setRef(String ref) {
      this.ref = ref;
    }

    @Override
    public String toString() {
      return " [id=" + id + ", targetCost="
    + targetCost + ", " + "actualCost=" 
          + actualCost + ", ref=" + ref
          + "]";
    }

  }// foo

  public static void main(String[] args) {

    List<Foo> list = Arrays.asList(

        new Foo(1, "P1", 300, 400), new Foo(2, "P2", 600, 400), new Foo(3, "P3", 30, 20),
        new Foo(3, "P3", 70, 20), new Foo(1, "P1", 360, 40), new Foo(4, "P4", 320, 200),
        new Foo(4, "P4", 500, 900)

    );
    // Method 1  : 
    Map<Integer, List<Foo>> collect = list.stream()
        .collect(
            Collectors.groupingBy(
                Foo::getId, 
                Collectors.collectingAndThen(

            Collectors.toList(),

            Function.identity()

        )// andthen

        )// gr

        );
    System.out.println(collect);
    /*
    {
        1=[ [id=1, targetCost=400, actualCost=300, ref=P1],
        id=1, targetCost=40, actualCost=360, ref=P1]],

         2=[ [id=2, targetCost=400, actualCost=600, ref=P2]],

          3=[ [id=3, targetCost=20, actualCost=30, ref=P3], 
           [id=3, targetCost=20, actualCost=70, ref=P3]], 

           4=[ [id=4, targetCost=200, actualCost=320, ref=P4], 
            [id=4, targetCost=900, actualCost=500, ref=P4]]

          }
  */

    // Method 2

    Map<Integer, List<Foo>> collect2 = list.stream().collect(
        Collectors.groupingBy(
            Foo::getId, 
            Collectors.mapping(
                Function.identity(), 
                Collectors.toList())));

    System.out.println(collect2);
    /*
     {
  1=[ [id=1, targetCost=400, actualCost=300, ref=P1], 
   [id=1, targetCost=40, actualCost=360, ref=P1]],

    2=[ [id=2, targetCost=400, actualCost=600, ref=P2]],

     3=[ [id=3, targetCost=20, actualCost=30, ref=P3],
       [id=3, targetCost=20, actualCost=70, ref=P3]],

        4=[ [id=4, targetCost=200, actualCost=320, ref=P4], 
         [id=4, targetCost=900, actualCost=500, ref=P4]]

       }

*/

    // Method 3 

    // If you need to compare something the you can use Compare.comparing

     Map<Integer, List<Foo>> collect3 = list
     .stream()
     .sorted( Comparator.comparing(Foo::getId)
         .thenComparing(Foo::getActualCost)
         .thenComparing(Foo::getTargetCost)    )

     .collect(                 

    Collectors.groupingBy(ch -> ch.id)     



         );

     System.out.println(collect3);


/*
{
  1=[ [id=1, targetCost=400, actualCost=300, ref=P1],  
  [id=1, targetCost=40, actualCost=360, ref=P1]],

   2=[ [id=2, targetCost=400, actualCost=600, ref=P2]],

    3=[ [id=3, targetCost=20, actualCost=30, ref=P3], 
     [id=3, targetCost=20, actualCost=70, ref=P3]],

      4=[ [id=4, targetCost=200, actualCost=320, ref=P4], 
       [id=4, targetCost=900, actualCost=500, ref=P4]]

     }
*/


  }// main

}

答案 5 :(得分:0)

与这个问题不完全相关,但是安静的类似情况。如果要按多个参数对列表进行分组,然后需要返回不同类型的对象作为值,则可以尝试此解决方案。 希望对某人有帮助!

public Map<Integer, Map<String, ObjectTypeB>> setObjectTypeB(List<ObjectTypeA> typeAList) {

   Map<Integer, Map<String, ObjectTypeB>> map = typeAList.stream()
        .collect(groupingBy(ObjectTypeA::getId,
         groupingBy(ObjectTypeA::getDate, 
         collectingAndThen(mapping(this::getObjectTypeB,toList()),values -> values.get(0)))));    
    return map;
}

    public ObjectTypeB getObjectTypeB(ObjectTypeA typeA) {
       ObjectTypeB typeB = new ObjectTypeB();
       typeB.setUnits(typeA.getUnits());
       return typeB;
}