如何使用java流将列表转换为具有多个键和值的映射作为列表

问题描述 投票:0回答:5

我有用户列表(id、ssn、名称),需要转换为 ssn 列表和 ids 列表的映射。你能帮忙解决这个问题吗?

List.of(new User(1, "ssn1", "user1"), new User(2, "ssn2", "user2"), new User(3, "ssn3", "user3"))

Map with 2 keys("SSNs","IDs") and list as value
"SSNs" -  List("ssn1","ssn2","ssn3")
"IDs" -  List(1,2,3)

代码

public class Test {

    public static void main(String[] args) {

        List<User> users = List.of(new User(1, "ssn1", "user1"), new User(2, "ssn2", "user2"),
                new User(3, "ssn3", "user3"));

        Map<String, List<Object>> userMap = users.stream().collect(Collectors.groupingBy(User::getSsn));
    
    }

}

class User {
    public int getId() {
        return id;
    }

    public String getSsn() {
        return ssn;
    }

    public String getName() {
        return name;
    }

    int id;
    String ssn;
    String name;

    public User(int id, String ssn, String name) {
        this.id = id;
        this.ssn = ssn;
        this.name = name;
    }
}

更新:将列表更新为列表。

java java-stream
5个回答
4
投票

这不一定是对 循环解决方案的改进,但您可以使用 Stream API 来解决任务,如下所示:

Map<String, List<Object>> result = users.stream()
    .collect(Collectors.teeing(
        Collectors.mapping(User::getId, Collectors.toList()),
        Collectors.mapping(User::getSsn, Collectors.toList()),
        (id, ssn) -> Map.of("IDs", id, "SSNs", ssn)));

上面的示例适用于 Eclipse。看起来,javac 在类型推断方面存在问题。以下内容适用于两者:

Map<String, List<Object>> result = users.stream()
    .collect(Collectors.teeing(
        Collectors.mapping(User::getId, Collectors.<Object>toList()),
        Collectors.mapping(User::getSsn, Collectors.<Object>toList()),
        (id, ssn) -> Map.of("IDs", id, "SSNs", ssn)));

或者

Map<String, List<?>> result = users.stream()
    .collect(Collectors.teeing(
        Collectors.mapping(User::getId, Collectors.toList()),
        Collectors.mapping(User::getSsn, Collectors.toList()),
        (id, ssn) -> Map.of("IDs", id, "SSNs", ssn)));

4
投票

一个简单的 for 循环可以解决您的问题,我建议使用这个简单的可读解决方案,而不是使用流:

Map<String, List<Object>> userMap = new HashMap<>();
userMap.put("SSNs", new ArrayList<>());
userMap.put("IDs", new ArrayList<>());
for (User user: users) {
    userMap.get("SSNs").add(user.getId());
    userMap.get("IDs").add(user.getSsn());
}

结果

{SSNs=[1, 2, 3], IDs=[ssn1, ssn2, ssn3]}

1
投票

您需要一个

Map
,它具有已知的恒定条目数 (2) 和一组已知的恒定密钥(“SSN”和“ID”)。听起来如果您只是将值保存在两个单独的变量中,而不是尝试将它们塞入两个条目的 Map 中,那么您的代码会简单得多。但是,如果您确实想要这样做,则必须将列表创建为
List<Object>
,而不是更自然的
List<String>
List<Integer>

    List<Object> ids = users.stream().map(user -> (Object) user.getId()).toList();
    List<Object> ssns = users.stream().map(user -> (Object) user.getSsn()).toList();
    Map<String, List<Object>> userMap = Map.of("IDs", ids, "SSNs", ssns);

0
投票

一定要考虑@Youcef的解决方案。试图做你想做的事情似乎真的会把事情搞得一团糟。见下图:

public class tester {
    public static void main(String[] args) {
        Map<String, Function<User, Object>> fields = new HashMap<>();
        fields.put("SSNs", User::getSsn);
        fields.put("Ids", User::getId);
        List<User> users = List.of(new User(1, "ssn1", "user1"), new User(2, "ssn2", "user2"),
                new User(3, "ssn3", "user3"));
        Map<String, List<Object>> map = fields.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> users.stream().map(u -> e.getValue().apply(u)).collect(Collectors.toList())));
        System.out.println(map);
//        Map<String, List<User>> userMap = users.stream().collect(Collectors.groupingBy(User::getSsn));
    }
}

输出:

{SSNs=[ssn1, ssn2, ssn3], Ids=[1, 2, 3]}

0
投票

我不明白在这里创建

Map
对您有什么好处。如果您需要将两个列表传递给一个函数,您最好创建一个包含两个列表的对象。

class UsersList {

    //... getters

    List<Integer> ids;
    List<String> ssns;

    public UsersList(List<User> users) {
        this.ids = new ArrayList<>();
        this.ssns = new ArrayList<>();
        users.forEach((u) -> {
            ids.add(u.getId());
            ssns.add(u.getSsn());
        });
    }
}

然后您可以将列表传递给构造函数,并且可以像这样访问两个列表:

   UsersList usersList = new UsersList(users);

   System.out.println("ids: " + usersList.ids);
   System.out.println("ssns: " + usersList.ssns);

编辑:更新了构造函数以使用 1 个流。

© www.soinside.com 2019 - 2024. All rights reserved.