有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何将list<SomeType>转换为映射,以保留所有重复的键和值

我的清单如下:

List<Address> address;

在哪里

Address:
city
country
state

我想把它转换成下面这样的东西

Map <String,String> convertedMap=list.stream().collect
(Collectors.toMap(Address:getCity+Address:getCountry ,Address:getState)); 

我希望在生成的映射中保留所有重复的键和值,如下所示

(key=City1country1, value= state1) ,(key=City1country1, value=state2),(key=City1country1,value= state1) ;

共 (4) 个答案

  1. # 1 楼答案

    这种类型的东西是许多编码挑战的常见要求,下面是一种快速完成所需内容的方法。如果您有时间限制,我选择使用集合而不是列表将查找时间设置为O(1)而不是O(N):

    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    class MapExample {
      public static void main(String[] args) {
        List<String> addressesList = new ArrayList<>();
        addressesList.add("Portland USA ME");
        addressesList.add("Portland USA OR");
        addressesList.add("Boston USA MA");
        System.out.println(cityToStatesMap(addressesList));
      }
    
      private static Map<String, Set<String>> cityToStatesMap(List<String> addressesList) {
        Map<String, Set<String>> result = new HashMap<>();
        if (addressesList == null || addressesList.size() == 0) {
          return result;
        }
        for (String address : addressesList) {
          String[] addressComponents = address.split(" ");
          String city = addressComponents[0];
          String country = addressComponents[1];
          String state = addressComponents[2];
          String key = city + country;
          Set<String> states = result.computeIfAbsent(key, k -> new HashSet<>());
          states.add(state);
          result.put(key, states);
        }
        return result;
      }
    }
    

    输出:

    {PortlandUSA=[ME, OR], BostonUSA=[MA]}
    
    注意:对于分隔符而不是空间,我认为你应该使用一个类似^ ^ {CD1>}的东西,这样就可以更容易地处理多个词的城市,例如纽约、旧金山等。
  2. # 2 楼答案

    如注释中所述,映射不存储重复的键,因此必须使用Map<String, List<String>>而不是Map<String, String>

    总之,您只需使用带有mergeFunction参数的Collectors.toMap方法,就可以处理重复的键。每次出现相同的键时都会调用此操作。在本例中,我们只需将两个列表合并为一个。看看下面的代码(用JDK11编译),我相信它完全满足您的需要,并打印出预期的结果(当然使用List<String>

    import java.util.*;
    import java.util.stream.Collectors;
    
    public class ListToMapWithDuplicatedKeysSample {
    
        public static void main(String[] args) {
            List<Address> addresses = List.of(
                    new Address("City1", "country1", "state1"),
                    new Address("City1", "country1", "state2"),
                    new Address("City1", "country1", "state1"),
                    new Address("City3", "country3", "state3")
            );
            Map<String, List<String>> result = addresses.stream()
                    .collect(
                            Collectors.toMap(
                                    address -> address.getCity() + address.getCountry(),
                                    address -> Collections.singletonList(address.getState()),
                                    ListToMapWithDuplicatedKeysSample::mergeEntriesWithDuplicatedKeys
                            )
                    );
            System.out.println(result);
        }
    
        private static List<String> mergeEntriesWithDuplicatedKeys(List<String> existingResults, List<String> newResults) {
            List<String> mergedResults = new ArrayList<>();
            mergedResults.addAll(existingResults);
            mergedResults.addAll(newResults);
            return mergedResults;
        }
    
        private static class Address {
    
            private final String city;
            private final String country;
            private final String state;
    
            public Address(String city, String country, String state) {
                this.city = city;
                this.country = country;
                this.state = state;
            }
    
            String getState() {
                return state;
            }
    
            String getCountry() {
                return country;
            }
    
            String getCity() {
                return city;
            }
        }
    }
    
  3. # 3 楼答案

    使用带有以下方法签名的toMap

       toMap(Function k, Function v,BinaryOperator m)
    

    BinaryOperator通知JVM如果遇到重复的密钥该怎么办。在您的情况下,如果它遇到重复的,则假定它将对它们进行跟踪

    因此,s1+”,“+s2

    因此,您的解决方案成为

      Map<String, String> map = list.stream().
                collect(Collectors.toMap((address -> {
                    String y = address.getCity() + address.getCountry();
                    return y + s;
                }), Address::getState, (s1, s2) -> s1 + "," + s2));
    

    输出

         country3City3  state3
         country1City1  state1,state2,state1
    
          Process finished with exit code 0
    
  4. # 4 楼答案

    你不能使用收集器。toMap,因为它需要唯一的键。您需要的是groupingBy,它返回每个键的收集值:

    class Location {
        public final String city;
        public final String country;
    
        Location(Address address) {
            this.city = address.getCity();
            this.country = address.getCountry();
        }
    
        @Override
        public boolean equals(Object obj) {
            if (obj instanceof Location) {
                Location other = (Location) obj;
                return Objects.equals(this.city, other.city) &&
                       Objects.equals(this.country, other.country);
            }
            return false;
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(city, country);
        }
    }
    
    Map<Location, Set<String>> statesByLocation = addresses.stream().collect(
        Collectors.groupingBy(Location::new,
            Collectors.mapping(Address::getState, Collectors.toSet())));
    

    您可以使用各种技巧来组合城市和国家(如两个字符串的列表),但您确实应该创建一个键类,如上图所示。代码将更容易使用,特别是如果您(或其他开发人员)有理由在六个月后重新使用它的话

    至于收集器方法:

    • Collectors.groupingBy(Location::new等价于address -> new Location(address)并在映射中创建每个键
    • Collectors.mapping(Address::getState, Collectors.toSet())意味着与特定键对应的每个地址都将在其上调用getState(),结果字符串将聚合在一个集合中以形成映射值

    就个人而言,我认为我会选择一个简单的for循环,而不是难以理解的流方法:

    Map<Location, Set<String>> statesByLocation = new HashMap<>();
    for (Address address : addresses) {
        statesByLocation.computeIfAbsent(new Location(address),
            k -> new HashSet<String>()).add(address.getState());
    }