【问题标题】:Efficient way to find the min/max of each field in an ArrayList of objects在对象的 ArrayList 中查找每个字段的最小值/最大值的有效方法
【发布时间】:2018-01-06 18:40:37
【问题描述】:

我有以下 ArrayList List<DataSt> list1 其中list1 具有以下值(浮点数):

<25.89,   21.23>
< 5.89,    1.23>
< 3.69,   20.23>
< 2.89,  121.23>
<125.89, 231.23>
.
.
.
< 28.89,  41.23>

DataSt具有以下结构:

public class DataSt {
    private float a;
    private float b;

    public DataSt(float a , float b){
        this.a=a;
        this.b=b;
    }
}

现在我需要从第一列中找到最小值,即从&lt;25.89, 5.89, 3.69, 2.89, 125.89 ... 28.89&gt; 它必须返回 2.89

然后从&lt;25.89, 5.89, 3.69, 2.89, 125.89 ... 28.89&gt;找到最大值,它必须返回125.89

现在对第二列重复相同的操作,并用 4 个不同的变量分别存储它们,例如 min_col1、max_col1、min_col2 和 max_col2。

min_col1 = 2.89
max_col1 = 125.89
min_col2 = 1.23
max_col2 = 231.23

我一直在寻找各种解决方案,这些解决方案建议使用两个 for 循环确实很耗时,还有一些线程建议使用 stream() 来查找整个列表(即,不是每一列)。

有没有一种有效的方法来做到这一点?我也在关注 Apache Commons。

【问题讨论】:

  • 到目前为止您尝试过什么?您在哪里遇到性能问题?
  • 如果你能分享你已经拥有的代码会很好。它表明您自己做出了努力,而不仅仅是在寻找为您编写代码的人。还可以更轻松地查看您是否在代码中犯了任何错误和/或是否可以改进
  • 请通过使用这些嵌套循环向我们展示您的努力。然后我们可以向您展示如何改进它。但是,如果您的代码完成了实际工作并且没有性能问题,为什么要更改有效的解决方案?
  • 你确实没有有一个二维数组。您有一个 1D 对象数组,每个对象包含 2 个浮点数。

标签: java arraylist max min


【解决方案1】:

很遗憾没有FloatStream,但您可以将值扩大到双倍,然后安全地缩小它们。

我假设您已经省略了 A 和 B 的吸气剂。

if (list1.isEmpty())
{
   throw /*something*/;
}
min_col1 = (float) list1.stream().mapToDouble(DataSt::getA).min().getAsDouble();
max_col1 = (float) list1.stream().mapToDouble(DataSt::getA).max().getAsDouble();
min_col2 = (float) list1.stream().mapToDouble(DataSt::getB).min().getAsDouble();
max_col2 = (float) list1.stream().mapToDouble(DataSt::getB).max().getAsDouble();

【讨论】:

  • 这是否比在min(),max() 中使用Comparator.naturalOrder().map() 而不是.mapToDouble 更有效?
  • 为什么这样更有效率?这样你最终会循环列表 4 次。
  • 我完全忽略了效率方面。如果没有衡量某件事是一个问题,或者没有定义一个效率目标,这是一个完全没有意义的要求。在实践中,这可能比基于 for 循环的解决方案的性能差得可以忽略不计,并且明显更加清晰和可维护。
【解决方案2】:

如果您只需要找到这些值,那么循环遍历列表一次就足够了。我建议学习一点大 O 表示法,以了解算法的性能。

你可以这样做:

float min_col1 = Float.MAX_VALUE;
float max_col1 = Float.MIN_VALUE;
float min_col2 = Float.MAX_VALUE;
float max_col2 = Float.MIN_VALUE;

for (DataSt data : list1) {

    if (data.getA() < min_col1) {
        min_col1 = data.getA();
    }

    if (data.getA() > max_col1) {
        max_col1 = data.getA();
    }

    if (data.getB() < min_col2) {
        min_col2 = data.getB();
    }

    if (data.getB() > max_col2) {
        max_col2 = data.getB();
    }
}

【讨论】:

  • 如果列表为空,您将不得不检查大量标记值。
  • 问题不在于处理边缘情况,是吗?这只是一次性完成的一般方法。
  • 好吧,要么在你的答案中提到这一点,要么改进代码,否则它是一个糟糕的答案。
  • 哦,拜托,在这种情况下,值只是保持设置为默认值。您的答案将在空列表上崩溃,大声笑。这里无事可做……再见。
  • 这不是一件坏事。尝试获取任何应该的最小值/最大值会导致异常。故障安全解决方案变得无法调试。
【解决方案3】:

我为你制作了一些样本。

    float Fmin = 0f;
    float Fmax = 0f;
    float Smin = 0f;
    float Smax = 0f;
    for (int i = 0; i < dataSts.size(); i++)
    {
        DataSt dataSt = dataSts.get(i);
        float a = dataSt.getA();
        float b = dataSt.getB();
        if(i == 0)
        {
            Fmin = a;
            Fmax = a;
            Smin = b;
            Smax = b;
            continue;
        }

        if(a < Fmin )
            Fmin = a;

        if(b < Smin )
            Smin = b;

        if(a > Fmax)
            Fmax = a;

        if(b > Smax)
            Smax = b;

    }
    System.out.println(Fmin +": "+Fmax+" : "+Smin+" : "+Smax);

【讨论】:

    猜你喜欢
    • 2015-05-22
    • 1970-01-01
    • 2016-01-05
    • 1970-01-01
    • 2015-07-21
    • 1970-01-01
    • 2019-04-22
    • 1970-01-01
    • 2012-08-30
    相关资源
    最近更新 更多