使用非最终变量将Java Map.Entry传输到流

时间:2017-02-07 17:31:24

标签: java java-8 java-stream

实际上这是LeetCode#56,我使用TreeMap来计算结果。

代码是:

public List<Interval> merge(List<Interval> intervals) {
    Map<Integer, Integer> tMap = intervals.stream().collect(Collectors.toMap(i -> i.start, i -> i.end, (i, j) -> i > j ? i : j));
    Map<Integer, Integer> map = new TreeMap<Integer, Integer> (tMap);
    List<Interval> res = new ArrayList<Interval>();
    int left = Integer.MAX_VALUE, right = Integer.MAX_VALUE, tmpLeft = -1, tmpRight = -1;
    Set<Map.Entry<Integer, Integer>> set = map.entrySet();
    for (Map.Entry<Integer, Integer> entry : set)
    {
        if (Integer.MAX_VALUE == left && Integer.MAX_VALUE == right)
        {
            left = entry.getKey();
            right = entry.getValue();
        }
        else
        {
            tmpLeft = entry.getKey();
            tmpRight = entry.getValue();
            if(right < tmpLeft)
            {
                res.add(new Interval(left, right));
                left = tmpLeft;
            }
            right = right > tmpRight ? right : tmpRight;
        }
    }
    if (Integer.MAX_VALUE != left && Integer.MAX_VALUE != right)
        res.add(new Interval(left, right));
    return res;
}

虽然它有效,但我想知道是否有办法在流中做到这一点。

  1. 可以通过流直接生成TreeMap Map<Integer, Integer> map = new TreeMap<Integer, Integer> (tMap);吗?

  2. 当我有Set<Map.Entry<Integer, Integer>> set及以下for循环时,是否有某种方法可以在流中执行此操作?

2 个答案:

答案 0 :(得分:1)

1-使用toMap收集器方法,该方法也接受Supplier<M>

Map<Integer, Integer> tMap = intervals.stream().collect(Collectors.toMap(i -> i.start, i -> i.end, (i, j) -> i > j ? i : j), () -> new TreeMap<Integer, Integer>());

2-您可以替换:

Set<Map.Entry<Integer, Integer>> set = map.entrySet();
for (Map.Entry<Integer, Integer> entry : set)
{ ...

使用:

map.entrySet().stream().forEach(entry -> { ...

但我认为这不值得。

答案 1 :(得分:1)

您可以将TreeMap创建简化为

Map<Integer, Integer> map = intervals.stream()
    .collect(Collectors.toMap(i -> i.start, i -> i.end, Math::max, TreeMap::new));

但实际上,TreeMap只是用于获取按起点排序的区间数据的kludge。虽然如果您确实需要排序存储,TreeMap就足够了,但对于一次性排序来说,它不是最有效的解决方案。

您可以使用:

intervals = intervals.stream()
    .sorted(Comparator.comparingInt(i -> i.start))
    .collect(Collectors.toList());
int left = Integer.MAX_VALUE, right = Integer.MAX_VALUE, tmpLeft = -1, tmpRight = -1;
 // proceed with your loop as before,
 // using i.start and i.end instead of entry.getKey() and entry.getValue()
for(Interval i: intervals)
{
    …

但是,在这里使用Collection API可能更有效:

intervals = new ArrayList<>(intervals);
intervals.sort(Comparator.comparingInt(i -> i.start));
int left = Integer.MAX_VALUE, right = Integer.MAX_VALUE, tmpLeft = -1, tmpRight = -1;
 // proceed with your loop as before,
 // using i.start and i.end instead of entry.getKey() and entry.getValue()
for(Interval i: intervals)
{
    …

在这两种情况下,都会创建一个新列表,假设您不想修改参数列表并独立于该列表的实现细节。

循环的逻辑可以表示为流操作,但它不会像循环那样简单。你需要一个自定义收集器,它带有你现在在循环中所做的几乎相同的操作,加上一个合并函数,它对两个列表做了类似的操作,以支持并行操作。