简体   繁体   English

列出<Object []>到java 8中的Map <K,V>

[英]List<Object[]> to Map<K, V> in java 8

Often there is the need to transform results for a query like: 通常需要为以下查询转换结果:

select category, count(*)
from table
group by category

to a map in which keys are categories and values are count of records belonging to the same category. 到一个映射,其中键是类别,值是属于同一类别的记录的数量。

Many persistence frameworks return the results of such a query as List<Object[]> , where object arrays contain two elements (category and the count for each returned result set row). 许多持久性框架返回像List<Object[]>这样的查询的结果,其中对象数组包含两个元素(类别和每个返回结果集行的计数)。

I am trying to find the most readable way to convert this list to the corresponding map. 我试图找到最可读的方式将此列表转换为相应的地图。

Of course, traditional approach would involve creating the map and putting the entries manually: 当然,传统方法包括创建地图并手动输入条目:

Map<String, Integer> map = new HashMap<>();
list.stream().forEach(e -> map.put((String) e[0], (Integer) e[1]));

The first one-liner that came to my mind was to utilize the out of the box available Collectors.toMap collector: 我想到的第一个单线程是利用开箱即用的Collectors.toMap收集器:

Map<String, Integer> map = list.stream().collect(toMap(e -> (String) e[0], e -> (Integer) e[1]));

However, I find this e -> (T) e[i] syntax a bit less readable than traditional approach. 但是,我发现这种e -> (T) e[i]语法比传统方法的可读性稍差。 To overcome this, I could create a util method which I can reuse in all such situations: 为了解决这个问题,我可以创建一个util方法,我可以在所有这些情况下重用它:

public static <K, V> Collector<Object[], ?, Map<K, V>> toMap() {
  return Collectors.toMap(e -> (K) e[0], e -> (V) e[1]);
}

Then I've got a perfect one-liner: 然后我有一个完美的单行:

Map<String, Integer> map = list.stream().collect(Utils.toMap());

There is even no need to cast key and value because of type inference. 由于类型推断,甚至不需要转换键和值。 However, this is a bit more difficult to grasp for other readers of the code ( Collector<Object[], ?, Map<K, V>> in the util method signature, etc). 但是,对于代码的其他读者(在util方法签名中的Collector<Object[], ?, Map<K, V>>等),这有点难以理解。

I am wondering, is there anything else in the java 8 toolbox that could help this to be achieved in a more readable/elegant way? 我想知道,java 8工具箱中还有什么可以帮助以更可读/更优雅的方式实现这一目标吗?

I think your current 'one-liner' is fine as is. 我认为你现在的'单线'很好。 But if you don't particularly like the magic indices built into the command then you could encapsulate in an enum: 但是,如果您不特别喜欢命令中内置的魔术索引,那么您可以封装在枚举中:

enum Column {
    CATEGORY(0), 
    COUNT(1);

    private final int index;

    Column(int index) {
        this.index = index;
    }

    public int getIntValue(Object[] row) {
        return (int)row[index]);
    }

    public String getStringValue(Object[] row) {
        return (String)row[index];
    }
}

Then you're extraction code gets a bit clearer: 然后你的提取代码变得更清晰了:

list.stream().collect(Collectors.toMap(CATEGORY::getStringValue, COUNT::getIntValue));

Ideally you'd add a type field to the column and check the correct method is called. 理想情况下,您需要向列添加类型字段并检查是否调用了正确的方法。

While outside the scope of your question, ideally you would create a class representing the rows which encapsulates the query. 虽然不在您的问题范围内,但理想情况下,您将创建一个表示封装查询的行的类。 Something like the following (skipped the getters for clarity): 类似下面的内容(为了清晰起见,跳过了吸气剂):

class CategoryCount {
    private static final String QUERY = "
        select category, count(*) 
        from table 
        group by category";

    private final String category;
    private final int count;

    public static Stream<CategoryCount> getAllCategoryCounts() {
        list<Object[]> results = runQuery(QUERY);
        return Arrays.stream(results).map(CategoryCount::new);
    }

    private CategoryCount(Object[] row) {
        category = (String)row[0];
        count = (int)row[1];
    }
}

That puts the dependency between the query and the decoding of the rows into the same class and hides all the unnecessary details from the user. 这将查询和行解码之间的依赖关系放入同一个类中,并隐藏用户的所有不必要的细节。

Then creating your map becomes: 然后创建地图变为:

Map<String,Integer> categoryCountMap = CategoryCount.getAllCategoryCounts()
    .collect(Collectors.toMap(CategoryCount::getCategory, CategoryCount::getCount));

Instead of hiding the class cast, I would make couple of functions to help with readability: 我没有隐藏类强制转换,而是提供了几个函数来帮助提高可读性:

Map<String, Integer> map = results.stream()
        .collect(toMap(
                columnToObject(0, String.class),
                columnToObject(1, Integer.class)
        ));

Full example: 完整示例:

package com.bluecatcode.learning.so;

import com.google.common.collect.ImmutableList;

import java.util.List;
import java.util.Map;
import java.util.function.Function;

import static java.lang.String.format;
import static java.util.stream.Collectors.toMap;

public class Q35689206 {

    public static void main(String[] args) {
        List<Object[]> results = ImmutableList.of(
                new Object[]{"test", 1}
        );

        Map<String, Integer> map = results.stream()
                .collect(toMap(
                        columnToObject(0, String.class),
                        columnToObject(1, Integer.class)
                ));

        System.out.println("map = " + map);
    }

    private static <T> Function<Object[], T> columnToObject(int index, Class<T> type) {
        return e -> asInstanceOf(type, e[index]);
    }

    private static <T> T asInstanceOf(Class<T> type, Object object) throws ClassCastException {
        if (type.isAssignableFrom(type)) {
            return type.cast(object);
        }
        throw new ClassCastException(format("Cannot cast object of type '%s' to '%s'",
                object.getClass().getCanonicalName(), type.getCanonicalName()));
    }
}

如何转换列表<object>至 Map<k, v> 使用 java stream<div id="text_translate"><p> 我想将List&lt;ObjectInList&gt;转换为Map&lt;K, V&gt;</p><pre> class ObjectInList { List&lt;Long&gt; listWithLong; Map&lt;String, Object&gt; dataMap; // there is 'id' key, and i want to use this id as key in map to be converted }</pre><p> 新的 map 格式如下</p><pre>String type; // this type is value of dataMap. List&lt;Long&gt; contents</pre><p> List&lt;Object&gt;中的每个 Object 都可以有重复的类型</p><p>例如</p><pre>///////// before converted //////////// [ { list: [1,2,3], dataMap: { type: "a", } }, { list: [4,5,6], dataMap: { type: "b", } }, { list: [7,8], dataMap: { type: "a", } }, ] ///////////// after converted ////////// { "a": [1,2,3,7,8], "b": [4,5,6] }</pre></div></k,></object> - How to convert LIst<Object> to Map<K, V> with using java stream

Java 8 转换一个List<object> 至 Map<k,v> 使用对象的孩子的领域?<div id="text_translate"><p> 情况很简单:我有一个 object List&lt;ParentClass&gt; list并想将其转换为Map&lt;orderKey, price&gt;</p><p> class 如下所示</p><pre>class ParentClass{ Child1Class a; Child2Class b; }</pre><p> orderKey class 看起来像这样</p><pre>class orderKey{ String id; String itemName; }</pre><p> 儿童班是这样的</p><pre>class Child1Class{ String id; String itemName; Date date; ..... } class Child2Class{ BigDecimal price; .... }</pre><p> 所有的类都有对应每个字段的 getter 和 setter。 所以我本质上是想 map 孩子们的领域。 我怎样才能做到这一点?</p><pre> -----------------------------MY ATTEMPT IS SOMETHING LIKE THIS-------------------------------------- list.stream(). .collect(Collectors.toMap(ParentClass::getA, ParentClass::getB).entrySet().stream()...... then I'm stuck</pre><p> 不知道如何构建临时 object orderKey作为新 map 的密钥。 任何帮助,将不胜感激。</p></div></k,v></object> - Java 8 convert a List<Object> to Map<K,V> using the fields of the object's children?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 转换清单 <Object> 到地图 <K,V> 在java中 - convert List<Object> to Map<K,V> in java Java 8转换地图 <K, List<V> &gt;到地图 <V, List<K> &gt; - Java 8 convert Map<K, List<V>> to Map<V, List<K>> 如何转换列表<object>至 Map<k, v> 使用 java stream<div id="text_translate"><p> 我想将List&lt;ObjectInList&gt;转换为Map&lt;K, V&gt;</p><pre> class ObjectInList { List&lt;Long&gt; listWithLong; Map&lt;String, Object&gt; dataMap; // there is 'id' key, and i want to use this id as key in map to be converted }</pre><p> 新的 map 格式如下</p><pre>String type; // this type is value of dataMap. List&lt;Long&gt; contents</pre><p> List&lt;Object&gt;中的每个 Object 都可以有重复的类型</p><p>例如</p><pre>///////// before converted //////////// [ { list: [1,2,3], dataMap: { type: "a", } }, { list: [4,5,6], dataMap: { type: "b", } }, { list: [7,8], dataMap: { type: "a", } }, ] ///////////// after converted ////////// { "a": [1,2,3,7,8], "b": [4,5,6] }</pre></div></k,></object> - How to convert LIst<Object> to Map<K, V> with using java stream Java 8 列表<V>进入地图<K, V>带功能 - Java 8 List<V> into Map<K, V> with Function Java 8 列表<V>进入地图<K, V> - Java 8 List<V> into Map<K, V> Java 8 列表<String>进入地图<String, K>其中 K 是一个在其构造函数中需要 V 的新对象 - Java 8 List<String> into Map<String, K> where K is a new object that needs V in its constructor Java 8 流映射<K,V>列出<T> - Java 8 stream Map<K,V> to List<T> Java 8将<T>列入Map <K,V> - Java 8 List<T> into Map<K, V> Java 8 转换一个List<object> 至 Map<k,v> 使用对象的孩子的领域?<div id="text_translate"><p> 情况很简单:我有一个 object List&lt;ParentClass&gt; list并想将其转换为Map&lt;orderKey, price&gt;</p><p> class 如下所示</p><pre>class ParentClass{ Child1Class a; Child2Class b; }</pre><p> orderKey class 看起来像这样</p><pre>class orderKey{ String id; String itemName; }</pre><p> 儿童班是这样的</p><pre>class Child1Class{ String id; String itemName; Date date; ..... } class Child2Class{ BigDecimal price; .... }</pre><p> 所有的类都有对应每个字段的 getter 和 setter。 所以我本质上是想 map 孩子们的领域。 我怎样才能做到这一点?</p><pre> -----------------------------MY ATTEMPT IS SOMETHING LIKE THIS-------------------------------------- list.stream(). .collect(Collectors.toMap(ParentClass::getA, ParentClass::getB).entrySet().stream()...... then I'm stuck</pre><p> 不知道如何构建临时 object orderKey作为新 map 的密钥。 任何帮助,将不胜感激。</p></div></k,v></object> - Java 8 convert a List<Object> to Map<K,V> using the fields of the object's children? 转换清单 <V> 在地图上 <K,V> 与流Java 8 - Convert List<V> in Map<K,V> with stream Java 8
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM