我需要找出属于另一个元素的最大元素。给你一个例子是最清楚的。
我的List<String> lines
包含以下数据:
1, 1, A, Aaa ...
1, 2, A, Aaa ...
1, 4, A, Aaa ...
2, 5, B, Bbb ...
2, 3, B, Bbb ...
3, 6, C, Ccc ...
4, 7, D, Ddd ...
5, 8, E, Eee ...
1, 9, A, Aaa ...
4, 10, D, Ddd ...
要清楚,2对数字永远不会相同,所以你永远不会得到:
1, 9, A, Aaa ...
1, 9, B, Bbb ...
我的目标是提取属于第一行的最大第二行的行。确切地说,这些行:
1, 9, A, Aaa ...
2, 5, B, Bbb ...
3, 6, C, Ccc ...
4, 10, D, Ddd ...
5, 8, E, Eee ...
为了证明你不是一个家庭作业,我已经使用多个for-loop
来找到最大值并存储到变量。但是我不知道它是否有效,因为测试了大量数据(200 000+
)。
// List "lines" is declared above
List<List<String>> data = new ArrayList<>();
List<List<String>> maxValues = new ArrayList<>();
// clear and separate to clear comparable parts
for (String s: lines) {
String parts[] = s.trim().replace("\"", "").split(";");
List newList = Arrays.asList(parts);
data.add(newList);
}
// naïve algorithm to find the maximum dependent to the another one
// not sure if working
for (List l: data) {
int id = Integer.parseInt(l.get(0).toString());
int max = 0;
List<String> tempMaxValues = new ArrayList<>();
for (int i=0; i<data.size(); i++) {
if (Integer.parseInt(l.get(0).toString()) == id) {
int temp = Integer.parseInt(l.get(1).toString());
if (temp > max) {
max = temp;
tempMaxValues = l;
}
}
}
maxValues.add(tempMaxValues);
}
此外,我需要做更多的计算。是否可以使用Stream
或更简单的方法达到我想要的结果?即使在我的代码中,我也会迷茫和困惑。
答案 0 :(得分:4)
在功能方面,您想要的是按照第一个元素对每个列表值进行分组,并仅选择与第二个元素相关的最大值。使用Stream API,您可以:
groupingBy(classifier, downstream)
收集器按列表的第一个元素进行分组。maxBy(comparator)
,它仅选择所收集值的最大值。在这种情况下,比较器在内置comparingInt
的帮助下将每个列表的第二个值与int
进行比较。maxBy
在未收集任何值的情况下返回Optional
,因此我们通过调用collectingAndThen(finisher)
对其进行包装,其中整理器检索Optional
值(我们在这种情况下,通过调用Optional.get()
来了解至少一个值已被分类。Map<String, List<String>>
中的values()
,因为这会返回Collection<List<String>>
,我们会根据它创建ArrayList
。示例代码:
List<List<String>> maxValues = new ArrayList<>(
data.stream()
.collect(Collectors.groupingBy(
l -> l.get(0),
Collectors.collectingAndThen(
Collectors.maxBy(Comparator.comparingInt(l -> Integer.parseInt(l.get(1)))),
Optional::get
)
))
.values()
);
导致
[1, 9, A, Aaa], [2, 5, B, Bbb], [3, 6, C, Ccc], [4, 10, D, Ddd], [5, 8, E, Eee]]
获取样本数据。
答案 1 :(得分:3)
对我来说,“天真”就像使用Map.merge()
通过唯一键(id值)来收集行一样:
static final Function<List<String>, Integer> GET_ID = l -> Integer.parseInt(l.get(0));
static final Function<List<String>, Integer> GET_TEMP = l -> Integer.parseInt(l.get(1));
Map<Integer, List<String>> max = new TreeMap<>();
for (List<String> l : data)
max.merge(GET_ID.apply(l), l, BinaryOperator.maxBy(Comparator.comparing(GET_TEMP)));
之后,只有具有相同身份的行中具有最大秒值的行将存储在max
地图中。
答案 2 :(得分:1)
另一种方法是使用toMap
收集器和BinaryOperator.maxBy
作为合并功能。给定List<String> lines
作为输入,您可以通过这种方式获得最佳字符串:
Collection<String> maxValues = lines.stream()
.collect(Collectors.toMap(
l -> l.split(",", 2)[0],
l -> l,
BinaryOperator.maxBy(Comparator.comparingInt(
l -> Integer.parseInt(l.split(",", 3)[1].trim()))))).values();
System.out.println(maxValues);
将合并运算符提取到变量时可能看起来更好:
BinaryOperator<String> maxBy = BinaryOperator.maxBy(Comparator.comparingInt(
l -> Integer.parseInt(l.split(",", 3)[1].trim())));
Collection<String> maxValues = lines.stream()
.collect(Collectors.toMap(l -> l.split(",", 2)[0], l -> l, maxBy)).values();
如果输入List<List<String>>
(已执行拆分和修剪),您可以通过以下方式找到Collection<List<String>>
:
BinaryOperator<List<String>> maxBy = BinaryOperator.maxBy(Comparator
.comparingInt(l -> Integer.parseInt(l.get(1))));
Collection<List<String>> maxValues = lines.stream()
.collect(Collectors.toMap(l -> l.get(0), l -> l, maxBy)).values();
答案 3 :(得分:0)
如果我很了解你可以使用其他方法解决你的问题; 首先:创建一个包含数据(对象)的类
public class DataObject {
int n1;
int n2;
String s1;
String s2;
}
创建对象列表:
List<DataObject> data = new ArrayList<DataObject>();
List maxVal = new ArrayList<DataObject>();
for (DataObject dO1 : data){
for (DataObject dO2 : data){
if (dO1.n1 == dO2.n2){
/*test to determin the max value and
*store it in maxVal
*/
}
}
}
这样可以更轻松地访问数据,或者我弄错了?