我的情况是这样的:
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class ObjectA {
int id;
LocalDate date;
int priorityA;
int priorityB;
}
List<ObjectA> list = List.of(
new ObjectA(1, LocalDate.parse("2021-09-22"), 2, 1),
new ObjectA(2, LocalDate.parse("2021-09-22"), 2, 1),
new ObjectA(3, LocalDate.parse("2022-09-22"), 2, 1),
new ObjectA(4, LocalDate.parse("2022-10-22"), 2, 1)
);
我必须折叠这些相隔不超过90天的物体。
要选择两个赢家中的哪一个,请选中:
我的执行情况如下:
List<ObjectA> collapsed = list.stream()
.collect(Collectors.collectingAndThen(
Collectors.groupingBy(
ObjectA::getDate,
Collectors.maxBy(Comparator
.comparing(ObjectA::getPriorityA)
.thenComparing(ObjectA::getPriorityB)
.thenComparing(ObjectA::getDate)
.thenComparing(ObjectA::getId))),
map -> map.values().stream()
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList())));
但是这个实现有两个问题:
通过适当的实施,我应该有如下示例:
ObjectA(1, LocalDate.parse("2021-09-22"), 2, 1)
ObjectA(2, LocalDate.parse("2021-09-22"), 2, 1)
ObjectA(3, LocalDate.parse("2022-09-22"), 2, 1)
ObjectA(4, LocalDate.parse("2022-10-22"), 2, 1)
that became
ObjectA(1, LocalDate.parse("2021-09-22"), 2, 1)
ObjectA(3, LocalDate.parse("2022-09-22"), 2, 1)
因为它们在第一对中具有相同的优先级和日期,所以我选择id最小的一对,而在第二对中,它们具有相同的优先级,但日期不同,所以我选择日期最小的一对。
心地善良的人能帮我吗?我在论坛上已经问过其他类似的问题,但我解释得不够好,答案也不令人满意。
编辑:“如果你有像A=2022-01-01、B=2022-03-01、C=2022-05-01这样的日期怎么办?A和B在90天之内,B和C在90天之内,但A和C在阈值之外。你是将A和B一起分组还是将B和C一起分组,为什么?”
另一个例子:
A-B取B,B-C取B,所以有了3,我只取B。
对于这种情况,使用stream、collect和Collector的解决方案可能不是最好的?
编辑:这是解决问题的另一种方法,我如何改进它?
// added a boolean in ObjectA -> "dropped" default false
for(int i = 0; i < list.size(); i++) {
for (int j = 1; j < list.size(); j++) {
if(list.get(i) == list.get(j) && (list.get(i).dropped || list.get(j).dropped))
continue;
long diff = ChronoUnit.DAYS.between(list.get(i).getDate(), list.get(j).getDate());
if(diff <= daysWindow && diff >= 0 && list.get(i) != list.get(j)) {
if (list.get(i).getPriorityA() != list.get(j).getPriorityA()) {
if (list.get(i).getPriorityA() > list.get(j).getPriorityA()) {
list.get(j).setDropped(true);
} else {
list.get(i).setDropped(true);
}
} else if (list.get(i).getPriorityB() != list.get(j).getPriorityB()) {
if (list.get(i).getPriorityB() > list.get(j).getPriorityB()) {
list.get(j).setDropped(true);
} else {
list.get(i).setDropped(true);
}
} else if (list.get(i).getDate().compareTo(list.get(j).getDate()) != 0){
if (list.get(i).getDate().compareTo(list.get(j).getDate()) > 0) {
list.get(i).setDropped(true);
} else {
list.get(j).setDropped(true);
}
} else {
if (list.get(i).getId()>list.get(j).getId()) {
list.get(i).setDropped(true);
} else {
list.get(j).setDropped(true);
}
}
}
}
}
// then i filter for take all objectA with dropped false.
谢谢大家能给的帮助。
尝试StreamEx.collapse:
final Comparator<ObjectA> cmp = Comparator.comparing(ObjectA::getPriorityA)
.thenComparing(ObjectA::getPriorityB)
.reversed()
.thenComparing(ObjectA::getDate)
.thenComparing(ObjectA::getId);
List<ObjectA> collapsed = StreamEx.of(list)
.collapse((a, b) -> ChronoUnit.DAYS.between(a.getDate(), b.getDate()) <= 90,
(a, b) -> cmp.compare(a, b) <= 0 ? a : b)
.toList();
在90天内选择一个任意的日期并按此分组是否有效?这似乎是一个简单的解决方案:
List<ObjectA> collapsed = list.stream()
.collect(Collectors.collectingAndThen(
Collectors.groupingBy(
x -> LocalDate.ofEpochDay(x.getDate().toEpochDay() % 90),
Collectors.maxBy(Comparator
.comparing(ObjectA::getPriorityA)
.thenComparing(ObjectA::getPriorityB)
.thenComparing(ObjectA::getDate)
.thenComparing(ObjectA::getId))),
map -> map.values().stream()
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList())));
如果我理解正确的话,这是一个两步排序问题。首先,您需要按日期对列表进行排序,以便能够在90天的时间间隔内对项目列表进行分组,然后根据您的优先级要求对组进行重新排序。
我将首先按日期对列表排序,并记住原子引用中第一个对象的日期。然后,通过查看每次迭代,查看当前对象的日期是否少于90天,可以使用此引用来形成组,如果是,则它属于当前组,否则将更新引用,并以新日期为关键字形成新组。然后对每个组的元素进行排序,并从每个组中提取第一个元素。要查看如何对由groupingBy
收集器生成的组进行排序,请参阅此post排序后的groupingBy列表。
示例代码,我用其他列表元素补充了该代码:
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import static java.time.temporal.ChronoUnit.DAYS;
public class Example {
public static void main(String args[]) {
List<ObjectA> list = List.of(
new ObjectA(1, LocalDate.parse("2021-09-22"), 2, 1),
new ObjectA(2, LocalDate.parse("2021-09-22"), 2, 1),
new ObjectA(3, LocalDate.parse("2022-09-22"), 2, 1),
new ObjectA(4, LocalDate.parse("2022-10-22"), 2, 1),
new ObjectA(10, LocalDate.parse("2025-09-22"), 2, 1),
new ObjectA(20, LocalDate.parse("2025-09-22"), 2, 1),
new ObjectA(30, LocalDate.parse("2025-09-23"), 2, 1),
new ObjectA(40, LocalDate.parse("2029-09-22"), 2, 1),
new ObjectA(13, LocalDate.parse("2029-09-22"), 2, 1),
new ObjectA(23, LocalDate.parse("2029-09-22"), 2, 1),
new ObjectA(33, LocalDate.parse("2029-09-22"), 2, 1),
new ObjectA(4, LocalDate.parse("2029-09-22"), 2, 1)
);
// for a better overview single comparators which are used as own variables
Comparator<ObjectA> byPrioA = Comparator.comparing(ObjectA::getPriorityA, Comparator.reverseOrder());
Comparator<ObjectA> byPrioB = Comparator.comparing(ObjectA::getPriorityB, Comparator.reverseOrder());
Comparator<ObjectA> byDate = Comparator.comparing(ObjectA::getDate);
Comparator<ObjectA> byId = Comparator.comparing(ObjectA::getId);
//first who has the largest "priorityA" attribute, if they are equal then
//check "priorityB", if this is also the same
//check the lesser date and if that is also the same then
//the one with the lesser id.
Comparator<ObjectA> combined = byPrioA.thenComparing(byPrioB).thenComparing(byDate).thenComparing(byId);
//sort list by date
List<ObjectA> sortedByDate = list.stream().sorted(byDate).collect(Collectors.toList());
//store first date for first group key
AtomicReference<LocalDate> ar = new AtomicReference<>(sortedByDate.get(0).getDate());
sortedByDate.stream().collect(Collectors.groupingBy(
d -> DAYS.between(ar.get(), d.getDate()) < 90 ? ar.get() : ar.accumulateAndGet(d.getDate(), (u,v) ->v),
LinkedHashMap::new,
Collectors.collectingAndThen(toSortedList(combined), l -> l.get(0))))
.values()
.forEach(System.out::println);
}
//https://stackoverflow.com/questions/35872236/sorting-lists-after-groupingby
static <T> Collector<T,?,List<T>> toSortedList(Comparator<? super T> c) {
return Collectors.collectingAndThen(
Collectors.toCollection(()->new TreeSet<>(c)), ArrayList::new);
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public static class ObjectA {
int id;
LocalDate date;
int priorityA;
int priorityB;
}
}
问题内容: 我有一列想要四舍五入到查询中的下一个较低的10分钟间隔(请参见下面的示例)。 我设法通过截断秒数然后减去分钟的最后一位来做到这一点。 结果如下: 01.01.2010 10: 00:00 听听01.01.2010 10: 00:00 01.01.2010 10: 05:00 听听01.01.2010 10: 00:00 01.01.2010 10: 9时59 听听01.01.2010
问题内容: 我正在使用PHPMyadmin,并使用PHP将值放入数据库中。我使用时间戳存储产品的到期日期,如下所示,例如: 我要选择所有到期日期等于今天的日期加上8天的日期(例如上面的那一天) 我也想在一个单独的页面中选择所有过期日期等于今天日期+ 2周的内容,如果有人可以帮助我,将不胜感激! 问题答案: 您可以使用以下查询来做到这一点: 您可以使用过去的日期。
问题内容: 我是bash的新手,我的任务是删除所有30天以上的文件,我可以根据文件名来解决这个问题 。 我知道我可以在包含文件的文件夹中列出所有文件。我知道我可以获取今天的日期,并可以对其进行配置以匹配文件格式 我知道我可以使用删除文件。 我如何将所有这些结合到一个bash脚本中,该脚本从今天起删除30天以上的文件? 在伪python代码中,我想它看起来像: 问题答案: 我绝不是系统管理员,但您可
问题内容: 我正在编写一个利用JavaScript超时和间隔来更新页面的应用程序。有没有办法查看设置了多少间隔?我想确保不会因设置数百个间隔而意外杀死浏览器。 这甚至是个问题吗? 问题答案: 我不认为有一种方法来枚举活动的定时器,但是你可以重写,并与自己的实现其做一些跟踪,然后调用原件替换它们。 当然,您不一定总是调用,但这至少可以为您提供某种方式来跟踪运行时发生的情况。
问题内容: 我正在使用MySQL,并且具有下表: 我希望能够生成这样的报告,其中在过去4周内完成了各个周期: 或最近3个月内: 有什么想法可以进行选择查询以生成等效的日期范围和点击次数吗? 问题答案:
我正在尝试将时间戳的时间为05:59:59 AM或以下的所有数据行转换为上一个日期。因此,例如“2018-12-08 05:05:00”将是“2018-12-07”,“2018-11-06 03:02:00”将是“2018-11-05”。 时间戳的格式为“yyyy-mm-dd hh:mm:ss”,并存储为varchar “从AWS Athena客户端引发错误。syntax_error:第1:17行