13r*_*ren 56 java collections data-structures
使用它会很好for (String item: list),但它只会迭代一个列表,而你需要一个显式的迭代器用于另一个列表.或者,您可以为两者使用显式迭代器.
以下是问题的示例,以及使用索引for循环的解决方案:
import java.util.*;
public class ListsToMap {
static public void main(String[] args) {
List<String> names = Arrays.asList("apple,orange,pear".split(","));
List<String> things = Arrays.asList("123,456,789".split(","));
Map<String,String> map = new LinkedHashMap<String,String>(); // ordered
for (int i=0; i<names.size(); i++) {
map.put(names.get(i), things.get(i)); // is there a clearer way?
}
System.out.println(map);
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
{apple=123, orange=456, pear=789}
Run Code Online (Sandbox Code Playgroud)
有更清晰的方法吗?也许在某处的馆藏API?
DrG*_*arl 47
从问这个问题已经有一段时间了,但是这些天我偏向于:
public static <K, V> Map<K, V> zipToMap(List<K> keys, List<V> values) {
return IntStream.range(0, keys.size()).boxed()
.collect(Collectors.toMap(keys::get, values::get));
}
Run Code Online (Sandbox Code Playgroud)
对于那些不熟悉流的人来说,这样做是IntStream从0到长度,然后将其打包,使其Stream<Integer>成为可以转换为对象,然后使用Collectors.toMap两个供应商收集它们,其中一个生成密钥,其他的价值观.
这可以进行一些验证(比如需要keys.size()小于values.size()),但它作为一个简单的解决方案很有效.
编辑:以上工作非常适合任何具有恒定时间查找的东西,但是如果你想要一些可以在同一个订单上运行的东西(并且仍然使用相同类型的模式),你可以做类似的事情:
public static <K, V> Map<K, V> zipToMap(List<K> keys, List<V> values) {
Iterator<K> keyIter = keys.iterator();
Iterator<V> valIter = values.iterator();
return IntStream.range(0, keys.size()).boxed()
.collect(Collectors.toMap(_i -> keyIter.next(), _i -> valIter.next()));
}
Run Code Online (Sandbox Code Playgroud)
输出是相同的(同样,缺少长度检查等),但时间复杂度不依赖于所get使用的任何列表的方法的实现.
Han*_*örr 41
我经常使用以下习语.我承认它是否更清楚是有争议的.
Iterator<String> i1 = names.iterator();
Iterator<String> i2 = things.iterator();
while (i1.hasNext() && i2.hasNext()) {
map.put(i1.next(), i2.next());
}
if (i1.hasNext() || i2.hasNext()) complainAboutSizes();
Run Code Online (Sandbox Code Playgroud)
它的优点是它也适用于集合和类似的东西,无需随机访问或没有有效的随机访问,如LinkedList,TreeSet或SQL ResultSet.例如,如果你在LinkedLists上使用原始算法,那么你需要一个缓慢的Shlemiel画家算法,它实际上需要对长度为n的列表进行n*n次操作.
正如13ren指出的那样,如果在长度不匹配时尝试读取一个列表的结尾后,您还可以使用Iterator.next抛出NoSuchElementException这一事实.所以你会得到更好的但可能有点令人困惑的变体:
Iterator<String> i1 = names.iterator();
Iterator<String> i2 = things.iterator();
while (i1.hasNext() || i2.hasNext()) map.put(i1.next(), i2.next());
Run Code Online (Sandbox Code Playgroud)
Mic*_*rdt 19
由于键值关系是通过列表索引隐式的,我认为显式使用列表索引的for循环解决方案实际上非常清楚 - 也很短.
sma*_*c89 12
另一个 Java 8 解决方案:
如果您有权访问 Guava 库(最早支持版本 21 [1] 中的流),您可以执行以下操作:
Streams.zip(keyList.stream(), valueList.stream(), Maps::immutableEntry)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
Run Code Online (Sandbox Code Playgroud)
对我来说,这种方法的优势在于它是一个评估为 a 的单一表达式(即一个行),Map我发现这对我需要做的事情特别有用。
CPe*_*ins 10
上面的解决方案当然是正确的,但你的问题是清晰度,我会解决这个问题.
组合两个列表的最明确方法是将组合放入一个名称清晰的方法中.我刚刚把你的解决方案解压缩到一个方法:
Map<String,String> combineListsIntoOrderedMap (List<String> keys, List<String> values) {
if (keys.size() != values.size())
throw new IllegalArgumentException ("Cannot combine lists with dissimilar sizes");
Map<String,String> map = new LinkedHashMap<String,String>();
for (int i=0; i<keys.size(); i++) {
map.put(keys.get(i), values.get(i));
}
return map;
}
当然,你重构的main现在看起来像这样:
static public void main(String[] args) {
List<String> names = Arrays.asList("apple,orange,pear".split(","));
List<String> things = Arrays.asList("123,456,789".split(","));
Map<String,String> map = combineListsIntoOrderedMap (names, things);
System.out.println(map);
}
我无法抗拒长度检查.
就个人而言,我认为一个简单的for循环迭代索引是最清晰的解决方案,但这里有两个可能的考虑因素.
这避免调用的替代Java的解决方案8 boxed()上的IntStream是
List<String> keys = Arrays.asList("A", "B", "C");
List<String> values = Arrays.asList("1", "2", "3");
Map<String, String> map = IntStream.range(0, keys.size())
.collect(
HashMap::new,
(m, i) -> m.put(keys.get(i), values.get(i)),
Map::putAll
);
);
Run Code Online (Sandbox Code Playgroud)
除了清晰度之外,我认为还有其他一些值得考虑的事情:
nullS(看看会发生什么,如果things是null在问题的代码).所以,对于库代码,可能是这样的:
@SuppressWarnings("unchecked")
public static <K,V> Map<K,V> linkedZip(List<? extends K> keys, List<? extends V> values) {
Object[] keyArray = keys.toArray();
Object[] valueArray = values.toArray();
int len = keyArray.length;
if (len != valueArray.length) {
throwLengthMismatch(keyArray, valueArray);
}
Map<K,V> map = new java.util.LinkedHashMap<K,V>((int)(len/0.75f)+1);
for (int i=0; i<len; ++i) {
map.put((K)keyArray[i], (V)valueArray[i]);
}
return map;
}
Run Code Online (Sandbox Code Playgroud)
(可能想检查不要放多个相等的键.)
| 归档时间: |
|
| 查看次数: |
59243 次 |
| 最近记录: |