使用LINQ或循环对相对接近的值进行分组



我想这比C#更像数学。我有一个浮点值数组,其中大多数值属于少数几个紧凑的范围之一。下面是一个例子(下限=0,上限=612):

3.4,5.0,6.1, 
144.0,144.14,145.0,147.0, 
273.77,275.19,279.0, 
399.4,399.91,401.45, 
533.26,537.0,538.9

这是一个由16个值组成的单个数组,只是将它们分隔开以显示这些"组"。我需要做的是以某种方式将它们分组,要么使用Linq,要么使用手动循环或其他方法,这样这些接近值就可以归入一组。

像除以10(或100)这样的简单数学运算是行不通的,因为399与401(上例中的第四组)属于不同的一组。另一种方法是创建某种直方图,但我在这里寻找一些简单的东西。如有任何帮助,我们将不胜感激。

只是使用GroupBy和自定义比较器进行集群的另一种想法

var numbers = new float[]
    {
       3.4f, 5.0f, 6.1f, 144.0f, 144.14f, 145.0f, 
       147.0f, 273.77f, 275.19f, 279.0f, 399.4f, 399.91f, 401.45f,
       49, 50, 51,
       533.26f, 537.0f, 538.9f
    };
foreach (var group in numbers.GroupBy(i => i, new ClosenessComparer(4f)))
    Console.WriteLine(string.Join(", ", group));

以及自定义ClosenessComparer:

public class ClosenessComparer : IEqualityComparer<float>
{
    private readonly float delta;
    public ClosenessComparer(float delta)
    {
        this.delta = delta;
    }
    public bool Equals(float x, float y)
    {
        return Math.Abs((x + y)/ 2f - y) < delta;
    }
    public int GetHashCode(float obj)
    {
        return 0;
    }
}

输出:

1: 3,4 5 6,1
2: 144 144,14 145 147
3: 273,77 275,19 279
4: 399,4 399,91 401,45
6: 49 50 51
5: 533,26 537 538,9

这里有一个方法,如果元素在前一个值的某个delta(默认为4)内,则对它们进行分组:

IEnumerable<IEnumerable<double>> GetClusters(IEnumerable<double> data,
                                             double delta = 4.0)
{
    var cluster = new List<double>();
    foreach (var item in data.OrderBy(x=>x))
    {
        if (cluster.Count > 0 && item > cluster[cluster.Count - 1] + delta)
        {
            yield return cluster;
            cluster = new List<double>();
        }
        cluster.Add(item);
    }
    if (cluster.Count > 0)
        yield return cluster;
}

您可以通过更改cluster[cluster.Count - 1] + delta使用的内容来调整算法。例如,您可以使用

  • cluster[0] + delta-来自集群中第一个元素的delta
  • cluster.Average() + delta-到目前为止集群平均值的delta
  • cluster[cluster.Count / 2] + delta-到目前为止集群中值的delta

相关内容

  • 没有找到相关文章