Java:如何将List 转换为Map
我想找到一种方法来获取下面的对象特定例程并将其抽象为一个方法,您可以传递一个类,列表和字段名来获取一个Map。 如果我可以在所使用的模式上获得一般指针,或者等等,这可以让我开始朝着正确的方向前进。
Map mapped_roles = new HashMap(); List p_roles = (List) c.list(); for (Role el : p_roles) { mapped_roles.put(el.getName(), el); }
这个? (伪代码)
Map MapMe(Class clz, Collection list, String methodName) Map map = new HashMap(); for (clz el : list) { map.put(el.methodName(), el); }
可能吗?
这就是我要做的。 我不完全确定我是否正确处理generics,但是哦,好吧:
public Map mapMe(Collection list) { Map map = new HashMap(); for (T el : list) { map.put(el.toString(), el); } return map; }
只需将Collection传递给它,让您的类实现toString()以返回名称。 多态性将照顾它。
使用Guava(以前的Google Collections) :
Map mappedRoles = Maps.uniqueIndex(yourList, Functions.toStringFunction());
或者,如果您想提供自己的方法,使得String
成为对象:
Map mappedRoles = Maps.uniqueIndex(yourList, new Function() { public String apply(Role from) { return from.getName(); // or something else }});
避免像瘟疫那样的reflection。
不幸的是,Java的语法很冗长。 (最近的JDK7提案会更加明确。)
interface ToString { String toString(T obj); } public static Map stringIndexOf( Iterable things, ToString toString ) { Map map = new HashMap(); for (T thing : things) { map.put(toString.toString(thing), thing); } return map; }
目前称为:
Map map = stringIndexOf( things, new ToString() { public String toString(Thing thing) { return thing.getSomething(); } );
在JDK7中,它可能是这样的:
Map map = stringIndexOf( things, { thing -> thing.getSomething(); } );
(那里可能需要yield
。)
Java 8流和方法引用使这很容易,你不需要一个帮助方法。
Map map = listOfFoos.stream() .collect(Collectors.toMap(Foo::getName, Function.identity()));
如果可能存在重复键,则可以使用带有值合并function的toMap重载来聚合这些值,或者可以使用groupingBy来收集列表:
//taken right from the Collectors javadoc Map> byDept = employees.stream() .collect(Collectors.groupingBy(Employee::getDepartment));
如上所示,这些都不是特定于String的 – 您可以在任何类型上创建索引。
如果你有很多要处理的对象和/或你的索引函数很昂贵,你可以使用Collection.parallelStream()
或stream().parallel()
( 他们做同样的事情 ) stream().parallel()
。 在这种情况下,您可以使用toConcurrentMap或groupingByConcurrent ,因为它们允许流实现只将元素爆炸到ConcurrentMap,而不是为每个线程制作单独的映射,然后合并它们。
如果您不想在调用站点提交Foo::getName
(或任何特定方法),则可以使用调用者传入的函数,存储在字段中等。实际创建函数的人仍然可以利用方法引用或lambda语法。
使用reflection和generics:
public static Map MapMe(Class clz, Collection list, String methodName) throws Exception{ Map map = new HashMap(); Method method = clz.getMethod(methodName); for (T el : list){ map.put((String)method.invoke(el), el); } return map; }
在您的文档中,请确保提及方法的返回类型必须是String。 否则,它会在尝试转换返回值时抛出ClassCastException。
如果您确定List
中的每个对象都有一个唯一索引,请使用Guava和Jorn建议的Maps.uniqueIndex
。
另一方面,如果多个对象可能具有相同的索引字段值(虽然对于您的特定示例而言不是这样,但在许多用例中这种情况也是如此),更常见的方法是这个索引是使用Multimaps.index(Iterable ImmutableListMultimap
,它将每个键映射到一个或多个匹配值。
这是一个使用自定义Function
的示例,该Function
在对象的特定属性上创建索引:
List foos = ... ImmutableListMultimap index = Multimaps.index(foos, new Function() { 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")) { ... }