简体   繁体   English

查找集合中的最低和最高 NUMBERS

[英]Find the lowest and highest NUMBERS in a collection

I have a List<BigDecimal> collection which contains (for the sake of simplicity) BigDecimal prices.我有一个List<BigDecimal>集合,其中包含(为了简单起见) BigDecimal价格。 I would like to process the collection and get:我想处理集合并得到:

  1. All of the highest prices.都是最高价。
  2. All of the lowest prices.都是最低价。

说明我的意思

My initial thoughts are to approach this using look-behind in order to decide if the numbers are moving in an up or down trend.我最初的想法是使用后视法来解决这个问题,以确定数字是在上升还是下降趋势中移动。 When the trend changes - determine which of the previous numbers are "highest" or "lowest" prices and then add them to the respectful List<BigDecimal> lowestPrices and List<BigDecimal highestPrices collections. For example, the first 3 dots are in an up-trend, but the 4th changes the trend to a down-trend.当趋势发生变化时——确定之前的数字中哪些是“最高”或“最低”价格,然后将它们添加到尊重的List<BigDecimal> lowestPricesList<BigDecimal highestPrices collections。例如,前 3 个点是向上的-trend,但是 4 号将趋势变为下降趋势。 So can now determine the min/max of the numbers before the change (0,1,2) and get the prices.所以现在可以确定更改前数字的min/max (0,1,2) 并获取价格。

I am not entirely sure if this isn't a naive approach so I was wondering if there would be the best approach to solving this issue in java?我不完全确定这是否是一种幼稚的方法,所以我想知道 java 中是否有解决此问题的最佳方法? Maybe a library that can already do this?也许图书馆已经可以做到这一点? (probably better not to re-invent the wheel) (最好不要重新发明轮子)

You are looking for local maxima (/minima).您正在寻找局部最大值(/最小值)。

Just look at whether the current point is greater (/less) than the point preceding and following it:只需查看当前点是否大于(/小于)其前后的点:

  • For a local maximum:对于局部最大值:

     list.get(i) > list.get(i - 1) && list.get(i) > list.get(i + 1)
  • For a local minimum:对于局部最小值:

     list.get(i) < list.get(i - 1) && list.get(i) < list.get(i + 1)

Pseudocode:伪代码:

for (int i = 1; i < list.size()-1; ++i) {
  if (local maximum) {
    // Add to list of local maxima
  } else if (local minimum) {
    // Add to list of local minima
  }
}

and handle the two endpoints as you desire.并根据需要处理这两个端点。

(You can also do this in ways that are more efficient for non-random access lists, eg LinkedList , using (List)Iterators; but the principle is the same). (您也可以使用 (List)Iterators 以对非随机访问列表更有效的方式执行此操作,例如LinkedList ;但原理是相同的)。

I decided to try implementing this, although I'm sure my implementation could be improved.我决定尝试实现这一点,尽管我确信我的实现可以改进。 The idea is just as you say, to keep track of the trend and record a local minimum or local maximum whenever the trend changes.这个想法就像你说的那样,跟踪趋势并在趋势发生变化时记录局部最小值或局部最大值。 There are two additional details to consider: first, initially we are not trending up or down, but the first value is either a minimum or maximum, so we have a third possibility for the trend, in addition to increasing or decreasing: inchoate;还有两个额外的细节需要考虑:首先,最初我们没有趋势向上或向下,但第一个值是最小值或最大值,因此除了增加或减少之外,我们还有第三种趋势可能性:早期; second, after the end of the loop we have to add the last item as either a minimum or maximum, depending on the direction the trend was going when we finished.其次,在循环结束后,我们必须添加最后一项作为最小值或最大值,具体取决于我们完成时趋势的方向。 Note that it will never add null if the list of prices is empty, because in that case, the trend would never have changed from inchoate.请注意,如果价格列表为空,它永远不会添加 null,因为在这种情况下,趋势永远不会从早期发生变化。

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Map;
import java.util.List;

public class Partition {
    public static void main(String[] args) {
        List<String> values = List.of("10.99", "15.99", "19.99", "12.99", "24.99",
            "21.99", "17.99", "11.99", "22.99", "29.99", "35.99", "27.99", "20.99");
        List<BigDecimal> prices = values.stream().map(BigDecimal::new).toList();
        Map<Extrema, List<BigDecimal>> part = new Partition().partitionExtrema(prices);
        System.out.format("Minima: %s%n", part.get(Extrema.MINIMA));
        System.out.format("Maxima: %s%n", part.get(Extrema.MAXIMA));
    }

    public Map<Extrema, List<BigDecimal>> partitionExtrema(List<BigDecimal> prices) {
        Trend trend = Trend.INCHOATE; // intially we don't know if we're going up or down
        List<BigDecimal> maxima = new ArrayList<>();
        List<BigDecimal> minima = new ArrayList<>();
        BigDecimal previous = null;
        for (BigDecimal current : prices) {
            int direction = previous == null ? 0 : current.compareTo(previous);
            if (direction > 0) {
                if (trend != Trend.DECREASING) {
                    minima.add(previous); // switching from decreasing to increasing
                }
                trend = Trend.INCREASING;
            }
            if (direction < 0) {
                if (trend != Trend.INCREASING) {
                    maxima.add(previous); // switching from increasing to decreasing
                }
                trend = Trend.DECREASING;
            }
            previous = current;
        }
        if (trend == trend.INCREASING) {
            maxima.add(previous);
        } else if (trend == trend.DECREASING) {
            minima.add(previous);
        }
        return Map.of(Extrema.MINIMA, minima, Extrema.MAXIMA, maxima);
    }
}

public enum Trend {
    INCREASING,
    DECREASING,
    INCHOATE
}

public enum Extrema {
    MAXIMA,
    MINIMA
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM