Java-8 Streams:转换Map <string,list <list <datatype =“”>&gt;&gt; to Map <string,list <datatype =“”>&gt;

时间:2017-05-01 13:59:54

标签: java java-8 java-stream

我刚开始看Java 8并试用lambdas,下面是我想要解决的问题

以下是我到目前为止的代码

type    P1     P2     P3    P4    device_ts
COV    2969                       2017-04-30  21:54:59
COV    2967                       2017-04-30  21:56:16
INT    2967                 2297  2017-04-30  22:00:00
COV    2965                       2017-04-30  22:08:00
INT    2966                 2301  2017-04-30  22:15:01
INT    2963                 2299  2017-04-30  22:30:03
COV    2961                       2017-04-30  22:35:00
COV    2963                       2017-04-30  22:43:40

上面的代码片段有效,但那不是我想要的。我希望它返回while($data = $P1->fetch(PDO::FETCH_ASSOC)) { if($data['type']=="INT") { echo "<tr>"; echo "<td>P1 value is : ".$data['P1']."</td>"; echo "<td>P2 value is : ".$data['P2']."</td>"; echo "<td>P3 value is : ".$data['P3']."</td>"; echo "<td>P4 value is : ".$data['P4']."</td>"; echo "<td>Time stamp. : ".$data['device_ts']."</td>"; echo "</tr>"; } }

我猜测平面映射的某种方式将解决问题

OperatorType枚举以供参考

    Map<String, List<List<DataType>>> a = Arrays.stream(OperatorType.values())
            .collect(
                    groupingBy(i -> i.getKey(), 
                            mapping(i -> i.getSupportedtypes(), 
                                    Collectors.toList()))); 

}

找到一种方法:

Map<String, List<DataType>>

4 个答案:

答案 0 :(得分:2)

我已经抛出了一些方法,并在你的枚举中用DataType切换了Integer,它现在看起来像这样:

enum OperatorType {
    IS_ONE_OF("IS_ONE_OF", 1,
           Collections.singletonList(1)),
    IS_NOT_ONE_OF("IS_NOT_ONE_OF", 2,
           Collections.singletonList(1)),
    ENDS_WITH("ENDS_WITH", 3,
           Collections.singletonList(2)),
    DOES_NOT_ENDS_WITH("DOES_NOT_ENDS_WITH", 4,
           Collections.singletonList(2)),
    STARTS_WITH("STARTS_WITH", 5,
           Collections.singletonList(2)),
    DOES_NOT_START_WITH("DOES_NOT_START_WITH", 6,
           Collections.singletonList(2)),
    MATCHES("MATCHES", 7,
           Collections.singletonList(2)),
    DOES_NOT_MATCH("DOES_NOT_MATCH", 8,
           Collections.singletonList(2)),
    CONTAINS("CONTAINS", 9,
           Collections.singletonList(2)),
    DOES_NOT_CONTAIN("DOES_NOT_CONTAIN", 10,
           Collections.singletonList(2)),
    GREATER_THAN("GREATER_THAN", 11, Arrays.asList(3,4)), 
    GREATER_THAN_OR_EQUAL_TO("GREATER_THAN_OR_EQUAL_TO", 12, Arrays.asList(3,4)), 
    LESS_THAN("LESS_THAN", 13, Arrays.asList(3,4)),
    LESS_THAN_OR_EQUAL_TO("LESS_THAN_OR_EQUAL_TO", 15, Arrays.asList(3,4)), 
    AFTER("AFTER", 15,
           Collections.singletonList(5)),
    BEFORE("BEFORE", 16,
           Collections.singletonList(5));

    private final int value;

    private final String key;

    private final List<Integer> supportedtypes;

    OperatorType(String key, int value, List<Integer> supportedtypes) {
       this.value = value;
       this.key = key;
       this.supportedtypes = supportedtypes;
    }

    public int getValue() {
       return this.value;
    }

    public String getKey() {
       return this.key;
    }

    public List<Integer> getSupportedtypes() {
       return this.supportedtypes;
    }

    @Override
    public String toString() {
       return String.valueOf(this.value);
    }
}

DataType切换回以下代码应该非常简单:

Map<String,List<Integer>> map = Arrays.stream(OperatorType.values()).collect(Collectors.toMap(OperatorType::getKey, OperatorType::getSupportedtypes));
map.forEach((k,v) -> System.out.println(k + " " + v));
System.out.println("");

Map<Integer,List<OperatorType>> map2 = 
        map.entrySet().stream()
        .flatMap(e -> e.getValue().stream().map(f -> new AbstractMap.SimpleEntry<>(f,e.getKey())))
        .collect(Collectors.groupingBy(r -> r.getKey(), Collectors.mapping(s -> Enum.valueOf(OperatorType.class, s.getValue()), Collectors.toList())));
map2.forEach((k,v) -> System.out.println(k + " " + v));

您可以将这两个步骤链接起来。但为了便于阅读,我将它们分开了。

对我来说,print语句打印如下:

DOES_NOT_CONTAIN [2]
STARTS_WITH [2]
LESS_THAN_OR_EQUAL_TO [3, 4]
DOES_NOT_MATCH [2]
AFTER [5]
DOES_NOT_ENDS_WITH [2]
IS_ONE_OF [1]
LESS_THAN [3, 4]
GREATER_THAN_OR_EQUAL_TO [3, 4]
CONTAINS [2]
DOES_NOT_START_WITH [2]
IS_NOT_ONE_OF [1]
BEFORE [5]
GREATER_THAN [3, 4]
ENDS_WITH [2]
MATCHES [2]

1 [2, 1]
2 [7, 3, 6, 9, 4, 8, 5, 10]
3 [11, 12, 13, 15]
4 [11, 12, 13, 15]
5 [16, 15]

我知道这个答案缺少一些解释,但它产生了你想要的Map<DataType,List<OperatorType>>

答案 1 :(得分:1)

看起来您的密钥与枚举名称相同。如果是这样的话:

a)你根本不需要钥匙;只需使用枚举常量的名称:

public String getKey() {
    return this.name();
}

b)由于密钥是唯一的,因此不需要分组。请改用toMap()收集器:

Map<String, List<DataType>> a = Arrays.stream(OperatorType.values())
        .collect(toMap(OperatorType::getKey, OperatorType::getSupportedtypes));

答案 2 :(得分:0)

您应该可以使用Stream#flatMap

Map<String, List<DataType>> map = new HashMap<>();

a.entrySet().forEach(entry -> {
    map.put(entry.getKey(), entry.getValue().stream()
                                            .flatMap(List::stream)
                                            .collect(Collectors.toList()));
});

由于List的每个值中List的{​​{1}}必须缩小,我们必须首先制作一个新的Map,然后重新添加元素凝聚每个Map

答案 3 :(得分:0)

一种方法是将收藏家toList替换为更合适的收藏家,例如reducing

Map<String, List<DataType>> a = Arrays.stream(OperatorType.values())
  .collect(
    groupingBy(i -> i.getKey(), 
      mapping(i1 -> i1.getSupportedtypes(),
        reducing((List<DataType>) new ArrayList<DataType>(), (l,r) -> {
          List<DataType> list = new ArrayList<DataType>();
          list.addAll(l);
          list.addAll(r);
          return list;
        })))); 

为了更好的可读性,提取二元运算符函数可能会有所帮助,例如: (l,r) -> join(l,r),其中join连接两个列表。