处理来自2个地图的数据以创建第3个地图

时间:2016-06-24 19:46:35

标签: java dictionary hashmap java-8

Map<String, List<myStruct>> map1 = ...;  
Map<String, List<myStruct>> map2 = ...; 

myStruct有2个字段:时间戳和数字。

我需要使用map1和map2中的键创建一个新的map3。对于每个键,每次map1和map2的时间戳匹配时,我都需要在myStrcts列表中添加一个新条目。该数字应该等于map1的数字除以地图2的数字。

例如,如果每个人都有1个条目:

Map<String, List<myStruct>> map1 = < "Cat" , < <1pm, 10> <2pm, 6>, <3pm, 8>>;  
Map<String, List<myStruct>> map2 = < "Cat" , < <1pm, 5> <2pm, 2>, <3pm, 1>>; 

然后

Map<String, List<myStruct>> map3 = < "Cat" , < <1pm, 2> <2pm, 3>, <3pm, 8>>; 

因为下午1点:10/5 = 2,下午2点:6/2 = 3,下午3点:8/1 = 8.

我曾尝试过使用lambda函数,但我无法提出任何好的和高效的东西。

我现在正在做的是迭代map1中的每个条目,然后遍历myStructs的每个时间戳 - 将它与map2中的时间戳进行比较,如果时间戳相等,则将结果添加到map 3。我试图找出一个更有效的解决方案。

3 个答案:

答案 0 :(得分:1)

您可以遍历map1的条目,然后通过流式传输地图的值来进行除法。

检查以下代码

简短代码

tmp是生成的List<myStruct>

 tmp = e.getValue()
        .stream()
        .map(struct -> new myStruct(struct.time, map2.get(e.getKey())
                                                           .stream()
                                                           .filter(x -> x.time.equals(struct.time))
                                                           .mapToInt(x -> struct.number / x.number)
                                                           .findFirst().getAsInt()))
        .collect(Collectors.toList());

长码

public static void main(String[] args) {
    Map<String, List<myStruct>> map1 = new HashMap<>();
    Map<String, List<myStruct>> map2 = new HashMap<>();

    myStruct one = new myStruct("1pm", 10);
    myStruct two = new myStruct("1pm", 5);
    myStruct thr = new myStruct("2pm", 6);
    myStruct fou = new myStruct("2pm", 2);
    myStruct fiv = new myStruct("3pm", 8);
    myStruct six = new myStruct("3pm", 1);

    map1.put("Cat", Arrays.asList(one, thr, fiv));
    map2.put("Cat", Arrays.asList(two, fou, six));

    Map<String, List<myStruct>> map3 = new HashMap<>(map1);

    List<myStruct> tmp;

    for (Map.Entry<String, List<myStruct>> e : map1.entrySet()) {
         tmp = e.getValue()
                .stream()
                .map(struct -> new myStruct(struct.time, map2.get(e.getKey())
                                                                   .stream()
                                                                   .filter(x -> x.time.equals(struct.time))
                                                                   .mapToInt(x -> struct.number / x.number)
                                                                   .findFirst().getAsInt()))
                .collect(Collectors.toList());

         map3.put(e.getKey(), tmp);
    }

    System.out.println(map3); // {Cat=[<1pm, 2>, <2pm, 3>, <3pm, 8>]}
}

答案 1 :(得分:0)

您可以这样做:

这是我的结构类,时间戳为字符串字段(不知道实际示例中使用的数据类型,这仅供参考)

public class Mystruct 
{
    private String timeStamp;
    private int number;

    public Mystruct(String timeStamp,int number) 
    {
        this.timeStamp=timeStamp;
        this.number=number;
    }

    public Mystruct() {
        // TODO Auto-generated constructor stub
    }

    public String getTimeStamp() {
        return timeStamp;
    }
    public void setTimeStamp(String timeStamp) {
        this.timeStamp = timeStamp;
    }
    public int getNumber() {
        return number;
    }
    public void setNumber(int number) {
        this.number = number;
    }

    @Override
    public String toString() {
        return "Mystruct [timeStamp=" + timeStamp + ", number=" + number + "]";
    }

}

测试课程:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Test {
    public static void main(String[] args) {
        Map<String, List<Mystruct>> map1 = new HashMap<String, List<Mystruct>>();
        Map<String, List<Mystruct>> map2 = new HashMap<String, List<Mystruct>>();

        List<Mystruct> list1 = new ArrayList<Mystruct>();
        List<Mystruct> list2 = new ArrayList<Mystruct>();

        Mystruct struct1 = new Mystruct("1PM", 10);
        Mystruct struct2 = new Mystruct("2PM", 6);
        Mystruct struct3 = new Mystruct("3PM", 8);
        list1.add(struct1);
        list1.add(struct2);
        list1.add(struct3);

        Mystruct struct4 = new Mystruct("1PM", 5);
        Mystruct struct5 = new Mystruct("2PM", 2);
        Mystruct struct6 = new Mystruct("3PM", 1);
        list2.add(struct4);
        list2.add(struct5);
        list2.add(struct6);

        map1.put("Cat", list1);
        map2.put("Cat", list2);

        List<Mystruct> list3 = null;
        List<Mystruct> list4 = null;

        Map<String, List<Mystruct>> map3 = new HashMap<String, List<Mystruct>>();
        for (String key : map1.keySet()) 
        {
            if(map2.get(key)!=null)
            {
                list3=map1.get(key);
                list4=map2.get(key);

                List<Mystruct> structList = new ArrayList<Mystruct>();

                for(Mystruct outerStruct:list3)
                {
                    for(Mystruct innerStruct:list4)
                    {
                        if(outerStruct.getTimeStamp().equals(innerStruct.getTimeStamp()))
                        {
                            Mystruct structToStore=new Mystruct();
                            structToStore.setTimeStamp(outerStruct.getTimeStamp());
                            structToStore.setNumber(outerStruct.getNumber()/innerStruct.getNumber());
                            structList.add(structToStore);
                        }

                    }
                }
                map3.put(key, structList);
            }
        }

        System.out.println(map3.toString());

    }

}
  

输出:

     

{Cat = [Mystruct [timeStamp = 1PM,number = 2],Mystruct [timeStamp = 2PM,   number = 3],Mystruct [timeStamp = 3PM,number = 8]]}

答案 2 :(得分:0)

这里有两个嵌套操作,合并地图并合并包含的列表。首先,我认为尝试在一个代码块中表达整个操作将变得非常难以理解。其次,合并这些List<myStruct>非常昂贵,特别是如果它们往往很大。因此,应首先将其中一个列表转换为Map<String,Integer>(假设String为时间戳值的类型),从而实现高效查找。在该地图上进行定位,将具有这样的地图的其他列表合并到结果列表可以表示为

static List<myStruct> combine(List<myStruct> list, Map<String,Integer> map) {
    return list.stream()
        .map(a -> {
            Integer b=map.get(a.getTimeStamp());
            return b==null? null: new myStruct(a.getTimeStamp(), a.getNumber()/b);
        })
        .filter(Objects::nonNull)
        .collect(Collectors.toList());
}

此实现关注其他地图中不存在的时间戳。如果总是有相应的条目,则该方法可以简化为

static List<myStruct> combineSimplified(List<myStruct> list, Map<String,Integer> map) {
    return list.stream()
        .map(a -> new myStruct(a.getTimeStamp(), map.get(a.getTimeStamp())/a.getNumber()))
        .collect(Collectors.toList());
}

使用列表组合方法,地图处理变得如

一样简单
// preparation step
Map<String, Map<String,Integer>> prep=map1.entrySet().stream()
    .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().stream()
        .collect(Collectors.toMap(myStruct::getTimeStamp, myStruct::getNumber))));

// final processing
Map<String, List<myStruct>> result = map2.entrySet().stream()
    .collect(Collectors.toMap(Map.Entry::getKey,
        e -> combine(e.getValue(), prep.get(e.getKey()))));

当然,您可以将列表组合方法内联到lambda表达式中,但我不推荐它。可读性会受到很大影响。