Java Stream API: 根据条件更改值

huangapple go评论79阅读模式
英文:

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 &quot;hh:mm:ss&quot;,

and ArrayList&lt;Item&gt; list which contains 10 elements.

So i want check my list and:

if now() - dateModified &gt; 1 min , then change color to 1
if now() - dateModified &gt; 5 min , then change color to 2
if now() - dateModified &gt; 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 -&gt; {
  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) &gt; 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&lt;Item&gt; items = new ArrayList&lt;&gt;(Arrays.asList(
                new Item(LocalTime.parse(&quot;10:30:00&quot;), 0),
                new Item(LocalTime.parse(&quot;10:30:01&quot;), 255)));

        LocalTime now = LocalTime.now();

        List&lt;Item&gt; modified = items.stream().map(item -&gt; {
            long minutes = Duration.between(item.dateModified, LocalTime.now())
                    .toMinutes();

            return minutes &gt;= 1 ? 
                    item.withColor(minutes &gt;= 10 ? 3 : minutes &gt;= 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&lt;Item&gt; items) {
    final LocalTime now = LocalTime.now();
    final Function&lt;Item, Long&gt; getDurationInMinutes = item -&gt; Duration.between(LocalTime.parse(item.dateModified), now).toMinutes()

    final Predicate&lt;Item&gt; betweenOneAndFive = item -&gt; {
        long duration = getDurationInMinutes.apply(item);
        return duration &gt; ONE &amp;&amp; duration &lt;= FIVE;
    };

    final Predicate&lt;Item&gt; betweenFiveAndTen = item -&gt; {
        long duration = getDurationInMinutes.apply(item);
        return duration &gt; FIVE &amp;&amp; duration &lt;= TEN;
    };

    final Predicate&lt;Item&gt; greaterThanTen = item -&gt; getDurationInMinutes.apply(item) &gt; TEN;


    items.stream().filter(betweenOneAndFive).forEach(item -&gt; item.color = 1);
    items.stream().filter(betweenFiveAndTen).forEach(item -&gt; item.color = 2);
    items.stream().filter(greaterThanTen).forEach(item -&gt; item.color = 3);
}

答案3

得分: 0

这涉及到从分钟差映射到数字的适当映射函数。

items.forEach(item -> item.setColor(((int) Math.floor(differenceInMinutes(item.getDateModified(), now) + 5)) / 5));

请注意,differenceInMinutes 方法将返回浮点数差异。

所采取的步骤如下:

  1. 计算项目日期与 now 之间的分钟差异。
  2. 将结果转换为 int 类型,其效果类似于 Math.floor
  3. 将结果加上 5。
  4. 除以 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 -&gt; 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:

  1. Find the difference in minutes from the date of the items with now.
  2. Cast the result to an int which will work like Math.floor.
  3. Add 5 to the result.
  4. 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&lt;Integer&gt; getNewColor(long elapseTimeSinceModification) {
	if (elapseTimeSinceModification &gt; 10) {
		return Optional.of(3);
	} else if (elapseTimeSinceModification &gt; 5) {
		return Optional.of(2);
	} else if (elapseTimeSinceModification &gt; 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&lt;Item&gt; itemsWithNewColor = items.stream()
		.map(item -&gt; getNewColor(getElapseTimeSinceModification(item))
				.map(newColor -&gt; withNewColor(newColor , item))
				.orElse(i))
		.collect(Collectors.toList());

huangapple
  • 本文由 发表于 2020年4月3日 21:43:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/61013288.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定