英文:
Java Stream API: Change values by criteria
问题
以下是Java代码的翻译部分:
有一个Java类:
public class Item {
private String dateModified;
private Integer color;
}
其中 `dateModified` 格式为 "hh:mm:ss",
以及包含 10 个元素的 `ArrayList<Item>` 列表。
所以我想要检查我的列表:
- 如果现在() - dateModified > 1 分钟,则将颜色更改为 1
- 如果现在() - dateModified > 5 分钟,则将颜色更改为 2
- 如果现在() - dateModified > 10 分钟,则将颜色更改为 3
如何使用 Java Stream API 实现它?
***更新:***
我用以下代码实现了我的任务。它按预期工作,但似乎很庞大且不够优雅。
我忘记说列表应该是可变的。
```java
list.stream()
.map(c -> {
if (compareTime(c.getDateModified(), 600)) {
c.setColor(3);
} else if (compareTime(c.getDateModified(), 300)) {
c.setColor(2);
} else if (compareTime(c.getDateModified(), 60)) {
c.setColor(1);
}
return c;
}).collect(Collectors.toList());
private boolean compareTime(String dateModified, Integer delta) {
boolean result = false;
LocalDateTime now = LocalDateTime.now();
int hour = now.getHour();
int minute = now.getMinute();
int second = now.getSecond();
Integer secondsDateModified = Integer.parseInt(dateModified.substring(0, 2)) * 3600 +
Integer.parseInt(dateModified.substring(3, 5)) * 60 +
Integer.parseInt(dateModified.substring(6, 8)) ;
Integer secondsNow = hour * 3600 + minute * 60 + second ;
Integer delta1 = secondsNow - secondsDateModified;
if ((delta1) > delta) {
result = true;
}
return result;
}
欢迎提出改进代码的建议。
英文:
There is Java class:
public class Item {
private String dateModified;
private Integer color;
}
where dateModified in format "hh:mm:ss",
and ArrayList<Item>
list which contains 10 elements.
So i want check my list and:
if now() - dateModified > 1 min , then change color to 1
if now() - dateModified > 5 min , then change color to 2
if now() - dateModified > 10 min, then change color to 3
How to implements it with Java Stream API?
UPDATE:
I implemented my task in such code below. It works as expected, but it seems huge and non-elegance.
I forget to say that list should be mutable.
list.stream()
.map(c -> {
if (compareTime(c.getDateModified(), 600)) {
c.setColor(3);
} else if (compareTime(c.getDateModified(), 300)) {
c.setColor(2);
} else if (compareTime(c.getDateModified(), 60)) {
c.setColor(1);
}
return c;
}).collect(Collectors.toList());
private boolean compareTime(String dateModified, Integer delta) {
boolean result = false;
LocalDateTime now = LocalDateTime.now();
int hour = now.getHour();
int minute = now.getMinute();
int second = now.getSecond();
Integer secondsDateModified = Integer.parseInt(dateModified.substring(0, 2)) * 3600 +
Integer.parseInt(dateModified.substring(3, 5)) * 60 +
Integer.parseInt(dateModified.substring(6, 8)) ;
Integer secondsNow = hour * 3600 + minute * 60 + second ;
Integer delta1 = secondsNow - secondsDateModified;
if ((delta1) > delta) {
result = true;
}
return result;
}
Any suggestions to improve the code are appreciated.
答案1
得分: 1
public static class Item {
private final LocalTime dateModified;
private final Integer color;
public Item(LocalTime dateModified, Integer color) {
this.dateModified = dateModified;
this.color = color;
}
public Item withColor(int color) {
return new Item(dateModified, color);
}
public LocalTime getDateModified() {
return dateModified;
}
public Integer getColor() {
return color;
}
}
示例
public static void main(String[] args) {
List<Item> items = new ArrayList<>(Arrays.asList(
new Item(LocalTime.parse("10:30:00"), 0),
new Item(LocalTime.parse("10:30:01"), 255)));
LocalTime now = LocalTime.now();
List<Item> modified = items.stream().map(item -> {
long minutes = Duration.between(item.dateModified, LocalTime.now())
.toMinutes();
return minutes >= 1 ?
item.withColor(minutes >= 10 ? 3 : minutes >= 5 ? 2 : 1) : item;
}).collect(Collectors.toList());
}
英文:
Instead of storing a String as the time, store a LocalTime object. Also, instead of mutating the original item, return the item or a new item with the new color.
public static class Item {
private final LocalTime dateModified;
private final Integer color;
public Item(LocalTime dateModified, Integer color) {
this.dateModified = dateModified;
this.color = color;
}
public Item withColor(int color) {
return new Item(dateModified, color);
}
public LocalTime getDateModified() {
return dateModified;
}
public Integer getColor() {
return color;
}
}
Example
public static void main(String[] args) {
List<Item> items = new ArrayList<>(Arrays.asList(
new Item(LocalTime.parse("10:30:00"), 0),
new Item(LocalTime.parse("10:30:01"), 255)));
LocalTime now = LocalTime.now();
List<Item> modified = items.stream().map(item -> {
long minutes = Duration.between(item.dateModified, LocalTime.now())
.toMinutes();
return minutes >= 1 ?
item.withColor(minutes >= 10 ? 3 : minutes >= 5 ? 2 : 1) : item;
}).collect(Collectors.toList());
}
答案2
得分: 0
关于使用单独的流来更新每个所需范围的项目,您可以考虑以下代码:
public static void updateColor(List<Item> items) {
final LocalTime now = LocalTime.now();
final Function<Item, Long> getDurationInMinutes = item -> Duration.between(LocalTime.parse(item.dateModified), now).toMinutes();
final Predicate<Item> betweenOneAndFive = item -> {
long duration = getDurationInMinutes.apply(item);
return duration > ONE && duration <= FIVE;
};
final Predicate<Item> betweenFiveAndTen = item -> {
long duration = getDurationInMinutes.apply(item);
return duration > FIVE && duration <= TEN;
};
final Predicate<Item> greaterThanTen = item -> getDurationInMinutes.apply(item) > TEN;
items.stream()
.forEach(item -> {
if (betweenOneAndFive.test(item)) {
item.color = 1;
} else if (betweenFiveAndTen.test(item)) {
item.color = 2;
} else if (greaterThanTen.test(item)) {
item.color = 3;
}
});
}
请注意,我对代码进行了一些调整,以便根据每个项目的时间差设置颜色。
英文:
What about to use separate streams for update each required range of items:
public static void updateColor(List<Item> items) {
final LocalTime now = LocalTime.now();
final Function<Item, Long> getDurationInMinutes = item -> Duration.between(LocalTime.parse(item.dateModified), now).toMinutes()
final Predicate<Item> betweenOneAndFive = item -> {
long duration = getDurationInMinutes.apply(item);
return duration > ONE && duration <= FIVE;
};
final Predicate<Item> betweenFiveAndTen = item -> {
long duration = getDurationInMinutes.apply(item);
return duration > FIVE && duration <= TEN;
};
final Predicate<Item> greaterThanTen = item -> getDurationInMinutes.apply(item) > TEN;
items.stream().filter(betweenOneAndFive).forEach(item -> item.color = 1);
items.stream().filter(betweenFiveAndTen).forEach(item -> item.color = 2);
items.stream().filter(greaterThanTen).forEach(item -> item.color = 3);
}
答案3
得分: 0
这涉及到从分钟差映射到数字的适当映射函数。
items.forEach(item -> item.setColor(((int) Math.floor(differenceInMinutes(item.getDateModified(), now) + 5)) / 5));
请注意,differenceInMinutes
方法将返回浮点数差异。
所采取的步骤如下:
- 计算项目日期与
now
之间的分钟差异。 - 将结果转换为
int
类型,其效果类似于Math.floor
。 - 将结果加上 5。
- 除以 5。
因此,例如 1.3 分钟将导致 (1+5)/5,结果为 1。
而 9.8 分钟将导致 (9+5)/5,结果为 2。
以此类推。
英文:
It is a matter of proper mapping function from difference of minutes to numbers.
items.forEach(item -> item.setColor(((int) Math.floor(differenceInMinutes(item.getDateModified(), now) + 5)) / 5));
Note, that the differenceInMinutes
method would return the difference in floating point arithmetic.
The steps taken are:
- Find the difference in minutes from the date of the items with
now
. - Cast the result to an
int
which will work likeMath.floor
. - Add 5 to the result.
- Divide by 5.
So, for example 1.3 minutes would result in (1+5)/5 which is 1.
9.8 minutes would result in (9+5)/5 which is 2.
And so on.
答案4
得分: 0
首先,正如Jason所说,不要在流内部更改项目,而是创建副本。
你需要中间操作:
long getElapseTimeSinceModification(Item item) {
return ChronoUnit.MINUTES.between(LocalTime.parse(item.dateModified), LocalDate.now());
}
Optional<Integer> getNewColor(long elapseTimeSinceModification) {
if (elapseTimeSinceModification > 10) {
return Optional.of(3);
} else if (elapseTimeSinceModification > 5) {
return Optional.of(2);
} else if (elapseTimeSinceModification > 1) {
return Optional.of(1);
}
return Optional.empty();
}
Item withNewColor(int newColor, Item item) {
Item newTtem = new Item();
newTtem.color = newColor;
newTtem.dateModified = item.dateModified;
return newTtem;
}
然后你可以将它们应用到你的流中:
List<Item> itemsWithNewColor = items.stream()
.map(item -> getNewColor(getElapseTimeSinceModification(item))
.map(newColor -> withNewColor(newColor, item))
.orElse(i))
.collect(Collectors.toList());
英文:
First, as Jason, said do not mutate yours items inside streams, make copies. (https://stackoverflow.com/questions/47041144/what-is-the-danger-of-side-effects-in-java-8-streams).
You will need intermediates operations :
long getElapseTimeSinceModification(Item item) {
return ChronoUnit.MINUTES.between(LocalTime.parse(item.dateModified), LocalDate.now());
}
Optional<Integer> getNewColor(long elapseTimeSinceModification) {
if (elapseTimeSinceModification > 10) {
return Optional.of(3);
} else if (elapseTimeSinceModification > 5) {
return Optional.of(2);
} else if (elapseTimeSinceModification > 1) {
return Optional.of(1);
}
return Optional.empty();
}
Item withNewColor(int newColor, Item item) {
Item newTtem = new Item();
newTtem.color = newColor;
newTtem.dateModified = item.dateModified;
return newTtem;
}
and then you can apply them to your stream :
List<Item> itemsWithNewColor = items.stream()
.map(item -> getNewColor(getElapseTimeSinceModification(item))
.map(newColor -> withNewColor(newColor , item))
.orElse(i))
.collect(Collectors.toList());
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论