当前位置: 首页 > 知识库问答 >
问题:

查找列表时间范围内元素的快速算法

高修筠
2023-03-14

问题是:我有一个包含时间和值(时间=长毫秒和双值)的数据列表。我现在需要计算不同时间范围内的几个平均值
我每秒最多可以得到50个值,但有时只有几个值,需要保持最后10秒,所以500个值。

我想要的是:计算时间的平均值

我可以保证没有时间是双倍的,所以它可以用作一把钥匙。

目前,我使用一个数组来存储值,并且有一个位置标记,一旦达到500,它就会重置为0,所以旧的条目会被重新调整样式。我可以很容易地改变。

我不确定最快的方法是什么,例如手动搜索数组或使用列表、hashMap、集合(使用comparator?)否则。我找不到一个类似(java)列表的函数,其中我有一个内置搜索键

性能比简单的编码更重要。

被指向正确的方向会很好。

每次有新值进来时,我都会计算最后10个值的平均值,即每秒30-50次计算,这是最重要的数据。我需要区分测量中的小错误和实际变化。我额外计算每1/10秒的平均值(这可能会被删除),最后是一秒的平均值和最后10秒的平均值。这是每秒12次的额外平均计算。减少计算次数并不是一个真正的选择。

由于这有点抽象,下面是一个数据的示例(其中avg是最后10个值的计算结果,但这不是程序逻辑)。

value           Avg timeReading timeReadingISO
1024,6668701172 -       1385408750828   2013-11-25 19:45:50
1024,6668701172 -       1385408751350   2013-11-25 19:45:51
1024,6668701172 -       1385408751859   2013-11-25 19:45:51
1024,6683349609 -       1385408752373   2013-11-25 19:45:52
1024,6683349609 -       1385408752878   2013-11-25 19:45:52
1024,6689453125 -       1385408753385   2013-11-25 19:45:53
1024,6689453125 -       1385408753895   2013-11-25 19:45:53
1024,6721191406 -       1385408754406   2013-11-25 19:45:54
1024,6721191406 -       1385408754912   2013-11-25 19:45:54
1024,6774902344 -       1385408755432   2013-11-25 19:45:55
1024,6774902344 1024,67 1385408755994   2013-11-25 19:45:55
1024,6774902344 1024,67 1385408756502   2013-11-25 19:45:56
1024,6837158203 1024,67 1385408757012   2013-11-25 19:45:57
1024,6837158203 1024,67 1385408757520   2013-11-25 19:45:57
1024,689453125  1024,68 1385408758028   2013-11-25 19:45:58
1024,689453125  1024,68 1385408758536   2013-11-25 19:45:58
1024,6938476563 1024,68 1385408759055   2013-11-25 19:45:59
1024,6938476563 1024,68 1385408759560   2013-11-25 19:45:59
1024,6990966797 1024,68 1385408760075   2013-11-25 19:46:00
1024,6990966797 1024,69 1385408760579   2013-11-25 19:46:00
1024,7038574219 1024,69 1385408761086   2013-11-25 19:46:01
1024,7038574219 1024,69 1385408761596   2013-11-25 19:46:01
1024,7111816406 1024,69 1385408762103   2013-11-25 19:46:02
1024,7111816406 1024,70 1385408762606   2013-11-25 19:46:02
1024,7111816406 1024,70 1385408763112   2013-11-25 19:46:03
1024,7111816406 1024,70 1385408763622   2013-11-25 19:46:03
1024,7172851563 1024,70 1385408764128   2013-11-25 19:46:04
1024,7172851563 1024,71 1385408764637   2013-11-25 19:46:04
1024,7208251953 1024,71 1385408765149   2013-11-25 19:46:05

1026,5457763672 -       1385474621756   2013-11-26 14:03:41
1026,6057128906 -       1385474621790   2013-11-26 14:03:41
1026,6257324219 -       1385474621823   2013-11-26 14:03:41
1026,6057128906 -       1385474621858   2013-11-26 14:03:41
1026,6257324219 -       1385474621890   2013-11-26 14:03:41
1026,6257324219 -       1385474621921   2013-11-26 14:03:41
1026,6057128906 -       1385474621956   2013-11-26 14:03:41
1026,5457763672 -       1385474621988   2013-11-26 14:03:41
1026,6557617188 -       1385474622022   2013-11-26 14:03:42
1026,6657714844 -       1385474622057   2013-11-26 14:03:42
1026,6257324219 1026,61 1385474622090   2013-11-26 14:03:42
1026,6057128906 1026,62 1385474622123   2013-11-26 14:03:42
1026,6657714844 1026,62 1385474622159   2013-11-26 14:03:42
1026,6557617188 1026,62 1385474622193   2013-11-26 14:03:42
1026,6557617188 1026,63 1385474622227   2013-11-26 14:03:42
1026,6257324219 1026,63 1385474622260   2013-11-26 14:03:42
1026,6257324219 1026,63 1385474622298   2013-11-26 14:03:42
1026,6557617188 1026,63 1385474622330   2013-11-26 14:03:42
1026,6257324219 1026,64 1385474622365   2013-11-26 14:03:42
1026,6257324219 1026,64 1385474622401   2013-11-26 14:03:42
1026,6257324219 1026,64 1385474622431   2013-11-26 14:03:42
1026,5758056641 1026,64 1385474622466   2013-11-26 14:03:42
1026,6057128906 1026,63 1385474622501   2013-11-26 14:03:42
1026,5457763672 1026,63 1385474622533   2013-11-26 14:03:42
1026,5457763672 1026,62 1385474622565   2013-11-26 14:03:42
1026,6057128906 1026,61 1385474622599   2013-11-26 14:03:42
1026,6057128906 1026,60 1385474622631   2013-11-26 14:03:42
1026,5758056641 1026,60 1385474622665   2013-11-26 14:03:42
1026,5457763672 1026,59 1385474622702   2013-11-26 14:03:42
1026,6057128906 1026,59 1385474622734   2013-11-26 14:03:42
1026,6557617188 1026,58 1385474622766   2013-11-26 14:03:42
1026,5758056641 1026,59 1385474622800   2013-11-26 14:03:42
1026,6057128906 1026,59 1385474622836   2013-11-26 14:03:42
1026,6057128906 1026,59 1385474622868   2013-11-26 14:03:42
1026,5158691406 1026,59 1385474622901   2013-11-26 14:03:42
1026,5457763672 1026,59 1385474622935   2013-11-26 14:03:42
1026,6856689453 1026,58 1385474622966   2013-11-26 14:03:42

共有2个答案

白烨煜
2023-03-14

在Maciej的答案中缓存平均值组是一种有效的方法。当前列表的一个简单方法是Java的SortedSet,它是一个接口,因此最终将使用TreeSet。

创建一个比较对象来存储时间和值,或者为SortedSet创建一个比较器。确保您是根据时间(而不是值)排序的。

public class Holder implements Comparable
{
  private double time, value;
  public Holder (double t, double v)
  {
    this.time = t;
    this.value = v;
  }

  public double getValue()
  {  return this.value; }

  public double getTime()
  {  return this.time; }

  //You may want a better comparator.
  public int compareTo( Holder h )
  {
    return this.getTime < h.getTime() ? -1 : 1;
  }
}

只需为集合添加正常值,它们将根据时间自动排序。当你想要过去10秒的平均值时,找到当前时间并调用sortedSet。tailSet(新的CustomObject(currentTime-10000))。现在迭代返回的集合以计算平均值。

SortedSet<Holder> slice = allHolders.tailset( new Holder( currentTime - 10000 ) );
double sum = 0.0;
for( Holder h : slice )
{
  sum += h.getValue();
} 
double result = sum / slice.size();

您可以使用查找时间组。subSet()如果您觉得平均呼叫有延迟。

闾丘诚
2023-03-14

首先,在计算平均值时,您应该创建一个结构的副本(或者使用一个线程安全的副本,并且在添加或删除过程中遍历它不会造成疼痛),除非您在一个线程中执行所有操作。

我猜你的集合中的元素是按区域排序的,因为你会按顺序接收更新(如果不是的话,请查找排序列表的等效项)。

我的方法是选择平均测量值的最小间隔。比如说10个值。然后,您可以创建50个集合(大小为10),其中每一个集合都属于同一级别,这为您提供了计算平均值的方法。然后,您可以选择要计算的平均值。只需计算集合的平均值 更重要的是,一旦计算出给定集合的平均值,就不会改变,所以可以缓存它

请注意,您不必将值从一个集合转移到另一个集合,因为已经处理了最小间隔。如果缓冲区中出现了新的10个元素,您只需重新分配引用即可。

/* initializing */
MySlicedCollection buffer = new MySlicedCollection();
MySlicedCollection[] mscArray = new MySlicedCollection[50];

/* when every 10 values came in */
for(int i = mscArray.length-1; i > 0 ; --i) {
    mscArray[i] = mscArray[i-1];
}
mscArray[0] = buffer;
buffer = new MySlicedCollection();

/* avg of all collection */
for(MySlicedCollection msc : mscArray) {
    sum += msc.getAverage();
}
sum /= 50;

你还应该考虑使用之前的结果计算平均值。如果你必须计算1秒和2秒的平均值,那么你可以把剩余的平均值加到已经计算的平均值上一秒钟,然后除以2。

/* avg for one second */
for(int i = 0; i < 5; ++i) {
    sumOneSec += mscArray[i].getAverage();
}
sumOneSec /= 5;

/* avg for two seconds */
for(int i = 5; i < 10; ++i) {
    sumTwoSec += mscArray[i].getAverage();
}
sumTwoSec = ((sumTwoSec/5) + sumOneSec) / 2;

但请记住有人说过的话:“先衡量然后行动”——也许你的表现就足够了?

avg = (avg * 50 - oldestValue + newValue)/50;

不幸的是,由于浮点变量的有限表示,这会给计算带来一点错误,但由于使用的是双值,我认为不需要这样的精度。类似的解决方案可以提供给另一个平均值,但这需要更多的思考:)

 类似资料:
  • 问题内容: 我有一个大约有450万行的Postgres表。列基本上只是 当查询该表,你有一个长整型,并希望找到对应的范围内的数据,并包括该值。索引此表以进行快速查找的最佳方法是什么? 问题答案: 一个 多列索引 具有反向排序顺序: 这样,可以将索引向前扫描到足够高的位置,然后对所有行进行扫描直到太低为止- 一次扫描。这就是为什么要对索引执行排序顺序的主要原因:将不同的排序顺序组合在具有不同顺序的多

  • 问题内容: 我知道范围有3种类型:范围,步幅和间隔。 快速间隔是多少?以及它们使用的一个例子是什么? http://zh.wikipedia.org/wiki/间隔(数学) 编辑:这就是beta 5 xcode 6发行说明所说的: •可比较值的间隔,可以有效地检查是否包含。间隔用于switch语句中的模式匹配,并由〜=运算符使用。 问题答案: 从Swift 3(使用Xcode 8)开始,类型不再存

  • 问题内容: 嗨,我正在尝试检查当前时间是否在某个时间范围内,例如8:00-16:30。下面的代码显示可以将当前时间作为字符串获取,但是不确定如何使用此值来检查它是否在上面指定的时间范围内。任何帮助将不胜感激! 问题答案: 有很多方法可以做到这一点。就我个人而言,如果可以避免的话,我不喜欢使用字符串。我宁愿处理日期组件。 下面的代码创建的日期为8:00和16:30,然后比较日期以查看当前日期/时间是

  • 问题内容: 我有一个元组列表,每个元组都是一个。我正在尝试合并所有重叠的时间范围,并返回不同时间范围的列表。例如 这是我的实现方法。 我想弄清楚是否 是某些python模块中的内置函数可以更有效地做到这一点吗?要么 有没有达到相同目标的更Python方式? 感谢您的帮助。谢谢! 问题答案: 使用Pythonic可以提高效率的几种方法: 消除了构造,因为该算法应在主循环中删除重复项。 如果只需要遍历

  • 问题内容: 例如,我有一个数字数组 我想找到特定范围内元素的所有索引。例如,如果范围是(6,10),则答案应该是(3,4,5)。有内置的功能可以做到这一点吗? 问题答案: 您可以用来获取索引并设置两个条件:

  • 问题内容: 给定一个数字列表,人们如何发现第()个元素与其第()个元素之间的差异? 使用表达式还是列表理解更好? 例如: 给定一个列表,我们的目标是要找到一个列表,因为,等等。 问题答案: