根据唯一值将列表拆分为子列表
Posted
技术标签:
【中文标题】根据唯一值将列表拆分为子列表【英文标题】:Splitting List into sublists based on unique values 【发布时间】:2015-05-13 14:57:35 【问题描述】:我有一个列表列表:
List<ArrayList<String>> D = new ArrayList<>();
填充后,它可能看起来像: [“A”、“B”、“Y”] [“C”、“D”、“Y”] [“A”、“D”、“N”]
我想根据唯一的属性值(假设索引 1)将列表列表拆分为分区。
所以索引 1 处的属性有两个唯一值,“B”和“D”,所以我想拆分为: [“A”、“B”、“Y”]
[“C”、“D”、“Y”] [“A”、“D”、“N”]
并将它们放入List<ArrayList<ArrayList<String>>> sublists;
有没有一种聪明的方法可以做到这一点,或者我只是做这样的事情:
List<ArrayList<ArrayList<String>>> sublists = new ArrayList<>();
int featIdx = 1;
// generate the subsets
for (ArrayList<String> record : D)
String val = record.get(featIdx);
// check if the value exists in sublists
boolean found = false;
for (ArrayList<ArrayList<String>> entry : sublists)
if (entry.get(0).get(featIdx).equals(val))
entry.add(record);
found = true;
break;
if (!found)
sublists.add(new ArrayList<>());
sublists.get(sublists.size()-1).add(record);
这是 C4.5 决策树 algorithm 的一个步骤,所以如果有人有这方面的经验,如果你能告诉我这是否是生成子列表的正确方法,我将不胜感激。
谢谢。
【问题讨论】:
【参考方案1】:我建议创建一个HashMap<String, List<List<String>>>
,并将这些列表分组。然后只需拨打map.values()
即可获得Collection<List<List<String>>>
。
List<List<String>> list = new ArrayList<>();
list.add(Lists.newArrayList("A", "B", "Y"));
list.add(Lists.newArrayList("C", "D", "Z"));
list.add(Lists.newArrayList("A", "D", "X"));
list.add(Lists.newArrayList("D", "C", "A"));
Map<String, List<List<String>>> mapped = list.stream()
.collect(Collectors.groupingBy(li -> li.get(1)));
System.out.println(mapped);
Collection<List<List<String>>> groupedList = mapped.values();
【讨论】:
【参考方案2】:在 Java 8 中,您可以使用 groupingBy
收集器:
Map<String, List<List<String>>> grouped = D.stream()
.collect(Collectors.groupingBy(list -> list.get(1)));
Collection<List<List<String>>> sublists = grouped.values();
或按照@AlexisC 的建议:
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.groupingBy;
Collection<List<List<String>>> sublists = D.stream()
.collect(collectingAndThen(groupingBy(list -> list.get(1)), Map::values));
【讨论】:
.. 或Collection<List<List<String>>> subLists = D.stream().collect(collectingAndThen(groupingBy(x -> x.get(1)), Map::values));
虽然,在这种情况下,我怀疑与你所做的有很大的不同(如果你在 collect
之后直接调用值)
我猜,collectingAndThen
仅在将生成的 Collector
传递到另一个复合 Collector
时才有用。否则,这只是在结果上调用方法的一种更复杂的方式。以上是关于根据唯一值将列表拆分为子列表的主要内容,如果未能解决你的问题,请参考以下文章