代码之家  ›  专栏  ›  技术社区  ›  ebt

Java:如何将列表转换为映射

  •  8
  • ebt  · 技术社区  · 14 年前

    我想找到一种方法,将下面的特定于对象的例程抽象为一个方法,您可以通过传递类、列表和字段名来获取映射。 如果我能得到一个关于所用模式的通用指针,或者,等等,这可以让我朝着正确的方向开始。

      Map<String,Role> mapped_roles = new HashMap<String,Role>();
        List<Role> p_roles = (List<Role>) c.list();
        for (Role el :  p_roles) {
            mapped_roles.put(el.getName(), el);
        }
    

    对这个(伪码)

      Map<String,?> MapMe(Class clz, Collection list, String methodName)
      Map<String,?> map = new HashMap<String,?>();
        for (clz el :  list) {
            map.put(el.methodName(), el);
        }
    

    6 回复  |  直到 14 年前
        1
  •  3
  •   quantumSoup    14 年前

    我会这么做。我不完全确定我是否正确处理了泛型,但是哦,好吧:

    public <T> Map<String, T> mapMe(Collection<T> list) {
       Map<String, T> map = new HashMap<String, T>();
       for (T el : list) {
           map.put(el.toString(), el);
       }   
       return map;
    }
    

        2
  •  33
  •   Pang Ajmal PraveeN    8 年前

    使用 Guava (formerly Google Collections) :

    Map<String,Role> mappedRoles = Maps.uniqueIndex(yourList, Functions.toStringFunction());
    

    String 在对象之外:

    Map<String,Role> mappedRoles = Maps.uniqueIndex(yourList, new Function<Role,String>() {
      public String apply(Role from) {
        return from.getName(); // or something else
      }});
    
        3
  •  4
  •   Jeffrey Bosboom    10 年前

    Java8流和方法引用使得这非常容易,您不需要一个helper方法。

    Map<String, Foo> map = listOfFoos.stream()
        .collect(Collectors.toMap(Foo::getName, Function.identity()));
    

    如果可能存在重复的键,则可以使用 toMap overload that takes a value merge function ,或者您可以使用 groupingBy 要收集到列表中:

    //taken right from the Collectors javadoc
    Map<Department, List<Employee>> byDept = employees.stream()
        .collect(Collectors.groupingBy(Employee::getDepartment));
    

    如果要处理很多对象和/或索引函数很昂贵,可以使用 Collection.parallelStream() stream().parallel() they do the same thing ). 那样的话你可以用 toConcurrentMap groupingByConcurrent ,因为它们允许流实现只将元素爆炸到ConcurrentMap中,而不是为每个线程创建单独的映射,然后合并它们。

    Foo::getName (或任何特定方法)在调用站点,您可以使用调用者传入的、存储在字段中的函数等。。无论是谁真正创建了函数,都可以利用方法引用或lambda语法。

        4
  •  3
  •   Tom Hawtin - tackline    14 年前

    不幸的是,Java的语法非常冗长(最近的一个JDK7提案将使它更具考虑性。)

    interface ToString<T> {
        String toString(T obj);
    }
    
    public static <T> Map<String,T> stringIndexOf(
        Iterable<T> things,
        ToString<T> toString
    ) {
        Map<String,T> map = new HashMap<String,T>();
        for (T thing : things) {
            map.put(toString.toString(thing), thing);
        }
        return map;
    }
    

    Map<String,Thing> map = stringIndexOf(
        things,
        new ToString<Thing>() { public String toString(Thing thing) {
            return thing.getSomething();
        }
    );
    

    Map<String,Thing> map = stringIndexOf(
        things,
        { thing -> thing.getSomething(); }
    );
    

    yield 在那里。)

        5
  •  1
  •   Michael    14 年前

    使用反射和泛型:

    public static <T> Map<String, T> MapMe(Class<T> clz, Collection<T> list, String methodName)
    throws Exception{
      Map<String, T> map = new HashMap<String, T>();
      Method method = clz.getMethod(methodName);
      for (T el : list){
        map.put((String)method.invoke(el), el);
      }
      return map;
    }
    

    在文档中,请确保提到方法的返回类型必须是字符串。否则,它将在尝试强制转换返回值时抛出ClassCastException。

        6
  •  1
  •   ColinD    14 年前

    如果你确定 List 将有一个唯一的索引,使用 Guava 乔恩建议 Maps.uniqueIndex .

    另一方面,如果不止一个对象的索引字段可能有相同的值(虽然对于您的特定示例可能不正确,但在这类事情的许多用例中都是正确的),那么更通用的索引方法是使用 Multimaps.index(Iterable<V> values, Function<? super V,K> keyFunction) 创建 ImmutableListMultimap<K,V>

    下面是一个使用自定义 Function 在对象的特定属性上创建索引的步骤:

    List<Foo> foos = ...
    ImmutableListMultimap<String, Foo> index = Multimaps.index(foos,
        new Function<Foo, String>() {
          public String apply(Foo input) {
            return input.getBar();
          }
        });
    
    // iterate over all Foos that have "baz" as their Bar property
    for (Foo foo : index.get("baz")) { ... }