3

我需要找到具有自己的统计信息(ResultGroup 类统计信息,基于所有结果统计信息)的对象列表的最大值、最小值和平均值(统计信息)值。当我添加对象时,值很容易更新,但如果我更改或删除其中一个,那么我需要再次查找统计信息。通常会有超过 40.000 个项目,我需要它来快速操作。

有没有比遍历所有项目更好的方法?

public class ResultGroup
{
    private Stats resultStats;
    //I need an updated stats
    public Stats ResultStats
    {
        get { return resultStats; }
    }
    private readonly ObservableCollection<Result> results = new ObservableCollection<Result>();

    public ObservableCollection<Result> Results
    {
        get
        {
            return results;
        }
    }
    public ResultGroup()
    {
        this.resultStats = new Stats();
        this.results.CollectionChanged += new NotifyCollectionChangedEventHandler(CollectionChanged);
    }

    private void CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Add)
        {
            //It works ok on add.
            Stats lastResultStat = this.results[this.results.Count - 1].Stat;
            if (resultStats.Max < lastResultStat.Max)
                resultStats.Max = lastResultStat.Max;

            if (resultStats.Min > lastResultStat.Min)
                resultStats.Min = lastResultStat.Min;

            resultStats.Mean = (resultStats.Mean * (this.results.Count - 1) + lastResultStat.Mean) / this.results.Count;
        }
        else if (e.Action == NotifyCollectionChangedAction.Reset)
        {
            this.resultStats = StatsFactory();
        }
        else if (e.Action == NotifyCollectionChangedAction.Remove)
        {
            //Need to find the stats here
        }
        else if (e.Action == NotifyCollectionChangedAction.Replace)
        {
            //Need to find the stats here
        }
    }

    private Stats StatsFactory()
    {
        Stats dataStats = new Stats();
        dataStats.Max = float.MinValue;
        dataStats.Min = float.MaxValue;
        dataStats.Mean = 0;
        return dataStats;
    }
}

public class Result
{
    private float[] data;

    //Another class will fill data and set the Stats (max, min, mean)
    public float[] Data
    {
        get { return data; }
    }

    public Result(int lenght)
    {
        this.data = new float[lenght];
    }

    private Stats stat;
    public Stats Stat
    {
        get { return stat; }
        set { stat = value; }
    }
}

public class Stats
{
    public float Max { get; set; }
    public float Min { get; set; }
    public float Mean { get; set; }
}
4

5 回答 5

3

当移除一个项目时,你只需要遍历所有项目,当移除的项目等于当前的最小值/最大值时。

当替换一个项目时,你只需要遍历所有项目,当删除的项目等于当前的最小值/最大值并且新的项目更大/更小。

于 2012-05-15T12:59:24.583 回答
1

我认为您可以在第一次初始化集合时缓存最大值、最小值,然后您可以将新值与缓存值进行比较。

我可以建议下一个算法:如果我有一个巨大的值列表,我会将其拆分为范围并为每个范围创建一个集合。对于每个集合,我都会有一个缓存的平均值,当集合发生变化时会重新计算该平均值。当我添加新值(或更改)时,我会看到元素的统计信息并找到具有所需范围的集合。在这种情况下,我们得到一个统计数据作为附加索引,我们必须仅在某些集合(第一个,最后一个)中找到最大值和最小值。我们可以从所有集合的平均值中得到的平均值。Max, Min 值我们也可以缓存在第一个和最后一个集合中。

于 2012-05-15T12:44:33.950 回答
1

您是否尝试过为此使用数据库?

因为数据库有索引可以提供帮助。还可以查看 KDB 或 SAP 的 HANA,它具有基于垂直/列的数据库,可以在几毫秒内渗透数百万行。

也许像 SqlLite 这样的基于文件的简单数据库会有所帮助。(如果您正在处理大量数据,这也应该有助于减少内存使用)

于 2012-05-15T12:45:25.377 回答
1

您是否尝试过在 CollectionChanged 中使用诸如 Min、Max 和 Average 之类的 LINQ 运算符?

于 2012-05-15T12:42:17.317 回答
0

//最好有一个自定义集合,其中包含集合内所需的属性,然后在集合顶部使用 linq 来存储聚合值...

 public class ObserCol: ObservableCollection<int>
{

    private int _maxValue = 0;

    public ObserCol() { 
        base.CollectionChanged +=new NotifyCollectionChangedEventHandler(CollectionChanged);
    }

    public int MaxValue{
        get {
            return _maxValue;
        }
    }

    private void CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Add)
        {
            //Can use Linq to get the Max or Other Aggregate values..
        }
        else if (e.Action == NotifyCollectionChangedAction.Reset)
        {

        }
        else if (e.Action == NotifyCollectionChangedAction.Remove)
        {

        }
        else if (e.Action == NotifyCollectionChangedAction.Replace)
        {

        }
    }
}
于 2012-05-15T13:31:05.260 回答