当前位置: 首页 > 知识库问答 >
问题:

Java 8:从2个列表中迭代并创建映射

宰父飞翼
2023-03-14

我有一个a类和B类的列表,没有重复的元素。“代码”属性在A类和B类中都是相同的。我想将它们转换为Map

public class A {
    private String code;
    private boolean status;
    field 3...
    field 4..

 
}

public class B {
    private String code;
    private String location;
    field 5...
    field 5..
}

public class C {
    private String location;
    private boolean status;
}

List1 : [A(code=NY, status=false), A(code=NJ, status=true),A(code=TX, status=true), A(code=NM, status=false)]

List2 : [B(code=NY, location=NewYork), B(code=NJ, location=NewJersey),B( code=TX, location=Texas), B(code=NM, location=NewMexico)]

Map =  map{NY=C(location=NewYork, status=false), NJ=C(location=NewJersey, status=true), TX=C(location=Texas, status=true),NM=C(location=NewMexico, status=false)}


最终映射的顺序应与列表1中的元素相同

~A

更新:我将代码更新到下面,但它不是编译的。你知道怎么了吗?

package test;

import java.util.*;
import java.util.stream.Collectors;

public class Test {

    static void main(String[] args){


        new Test().testFunction();

    }

      void testFunction(){


        System.out.println("Hello World");



        List<A> listA = Arrays.asList(new A("NY", false), new A("NJ", true), new A("TX", false), new A("AZ", true));
        List<B> listB = Arrays.asList(new B("NY", "New York"), new B("NJ", "New Jersey"),
                new B("TX", "Texas"), new B("NM", "New Mexico"));


        Map<String, B> mapB = listB
                .stream()
                .collect(Collectors.toMap(B::getCode, b -> b, (b1, b2) -> b1));

        Map<String, C> innerJoin = listA
                .stream()
                .filter(a -> mapB.containsKey(a.getCode())) // make sure a B instance exists with the code
                .map(a -> Map.entry(a.getCode(), new C(mapB.get(a.getCode()).getLocation(), a.getStatus())))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (c1, c2) -> c1, HashMap::new));

        innerJoin.forEach((code, c) -> System.out.println(code + " -> " + c));

    }

}


     class A {
        private String code;
        private boolean status;

         public A(String code, boolean status) {
             this.code = code;
             this.status = status;
         }
         public String getCode() {
             return this.code;
         }
         public boolean getStatus() {
             return this.status;
         }
     }

     class B {
        private String code;
        private String location;

         public B(String code, String location) {
             this.code = code;
             this.location = location;
         }

         public String getCode() {
             return this.code;
         }
         public String getLocation() {
             return this.location;
         }
     }

     class C {
        private String location;
        private boolean status;

         public C(String location, boolean status) {
             this.location = location;
             this.status = status;
         }
         public String getLocation() {
             return this.location;
         }
         public boolean getStatus() {
             return this.status;
         }
    }

共有3个答案

卢杰
2023-03-14

这个任务似乎是通过一个键属性连接两个对象列表。考虑到需求,它应该像内连接一样借助从listB创建的临时映射。

Map<String, B> mapB = listB
        .stream()
        .(Collectors.toMap(B::getCode, b -> b, (b1, b2) -> b1)); // use merge function as a defense measure

Map<String, C> innerJoin = listA
        .stream()
        .filter(a -> mapB.containsKey(a.getCode())) // make sure a B instance exists with the code
        .map(a -> Map.entry(a.getCode(), new C(mapB.get(a.getCode()).getLocation(), a.isStatus())))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (c1, c2) -> c1, LinkedHashMap::new));

测试:

List<A> listA = Arrays.asList(new A("NY", false), new A("NJ", true), new A("TX", false), new A("AZ", true));
List<B> listB = Arrays.asList(new B("NY", "New York"), new B("NJ", "New Jersey"), new B("TX", "Texas"), new B("NM", "New Mexico"));

// ...
innerJoin.forEach((code, c) -> System.out.println(code + " -> " + c));

输出:

NY -> C(location=New York, status=false)
NJ -> C(location=New Jersey, status=true)
TX -> C(location=Texas, status=false)

“最简单”的解决方案可能基于这样的假设,即两个列表中的项目由相同的code字段“排序”,那么不需要临时映射:

Map<String, C> simple = IntStream
        .range(0, listA.size())
        .mapToObj(i -> Map.entry(listA.get(i).getCode(), new C(listB.get(i).getLocation(), listA.get(i).isStatus())))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (c1, c2) -> c1, LinkedHashMap::new));

然而,这样的解决方案太脆弱了。

魏兴邦
2023-03-14
java prettyprint-override">Map<String, C> map = IntStream.range(0, list1.size())
    .mapToObj(i -> new CodeIndex(list1.get(i).code(), i))
    .collect(Collectors.toMap(
        CodeIndex::code,
        ci -> new C(list2.get(ci.index()).location(), list1.get(ci.index()).status()),
        (a, b) -> a,
        LinkedHashMap::new
    ));

我们首先获取两个列表的所有有效索引,然后映射到一个(自定义)容器类,其中包含索引和代码。(我称之为CodeIndex,但您也可以使用Map.Entry或一些Pair类。)

最后,我们将其收集到一个LinkedHashMap(因为它保留了插入顺序),将键映射到简单的CodeIndex::code,并将值映射到新的C(«location\u from_list2»,«status\u from_list1»)

请注意,此代码遍历列表一次。

当然,这是假设:

  • 两个列表具有相同的代码;
  • list1和list2的所有代码顺序相同。

请注意,我使用了记录样式的getter,即与相应字段名同名的getter。例如,location()而不是getLocation()

漆雕深
2023-03-14

你应该使用这样的东西:

Map<String, B> mapList2 = list2.stream().collect(Collectors.toMap(B::getCode, 
    Function.identity()); // create temporary map

Map<String,B> result = list1.stream().collect(
            LinkedHashMap::new,
            (map, a) -> map.put(
                   a.getCode(), // get code from A
                   new C(
                           mapList2.get(a.getCode()).getLocation() // get location from B
                           a.getStatus() // get status from A
                   ),  
             Map::putAll); // use LinkedHashMap to keep order       
 类似资料:
  • 我有两份清单: 列表1: Object1(name1, id1) 列表2: Object2(name2, id2) 给定list1的大小与list2相同 我想迭代list2,如果list2的name2不为null,则更新list1的name1。 以下是使用旧java的代码: 用java实现这一点的最佳方法是什么。util。流动

  • 我在迭代一个对象内的列表时遇到了一个问题,该对象内嵌在另一个映射中。我的目标是迭代这个列表并生成一个映射 ,我希望使用streams和lamdas来实现这一点。 我在上面看到了,我需要通过迭代FolderBo中的elementList从elementBo创建一个带有map 的映射。folderBo本身就在Modelbo的地图内。

  • 我有以下课程: 我想使用Java流创建一个

  • 是否可以从迭代器创建一个流,其中对象的序列与通过反复调用迭代器的next()方法生成的序列相同?我所考虑的具体情况涉及到Treeset.desceningIterator()返回的迭代器的使用,但是我可以想象在其他情况下,迭代器是可用的,而不是它所引用的集合。 例如,对于,我们可以编写并按照该集合的排序顺序获取该集合中的对象流,但是如果我们希望它们按照不同的顺序,比如通过使用获得的顺序呢?我想象的

  • 我想知道,如何在Java8中使用流API迭代多级列表 根据Java8,我应该做如下的操作 我想要流利地做这件事(使用内部迭代)。任何解释都会很感激。

  • 我有一个学生名单a和学生名单B。 学生对象包含如下字段:否、年龄、城市、出生日期、工资 我的列表A包含这些对象 我的列表B包含这些对象 我想做的是提取ListA有但listB没有的学生对象,以及ListA和listB有但薪水不同的学生对象(如否、年龄、城市)。我还想写工资差异。 我想在java 8中使用流api。首先,我想将students对象提取到列表中,但我现在可以提取常见的student对象