仍在玩推特趋势。 我收集了足够的数据,希望加快处理速度。 我想通过使用以趋势词索引的关联数组为每个趋势词分配一个整数索引。 下面提供了三种向表中添加新单词或获取旧单词索引的技术。
第一个使用 TRY 来捕获单词不在表中时的异常。 如果单词存在,它是最快的;如果发生异常,它是最慢的(到目前为止)。
第二个使用 CONTAINS 来测试该单词是否存在,然后添加它或查找它。 它的添加速度最快,查找速度最慢(因为它查找两次。)
最后一个使用关联数组默认值来查看检索到的值是否已存在。 它提供了一个很好的折衷速度。
所有示例都有一个运行两次的“t”循环。 第一次 xN 数组为空,必须填充。 第二次时,所有值都已存在。
// Three ways to build a lookup table. No clear winner!
// Goal: assign an integer, starting at 1, to each new
// entry. For timing purposes, use the integer as the
// key and the value. The key will be a string in real
// code. The value will be used as an index elsewhere.
explain = {"create new entry","use existing entry"};
N = 1e5; // several seconds at 1e5
/*
Use TRY to determine when an entry needs to be created.
On the "catch" create the entry. If there is no catch,
the value is already fetched. The "t" loop runs 20X
slower the first time because the "catch" is expensive.
But the second time the "t" loop is the fastest solution.
*/
x1 = [=> ];
For( t = 1, t <= 2, t += 1,
start = HP Time();
For( ix = 1, ix < N, ix += 1,
Try( y = x1[ix], y = (x1[ix] = ix) )
);
stop = HP Time();
Write( Eval Insert( "\!nTry method: ^char((stop - start)/1e6,5,3)^ seconds ^explain[t]^" ) );
);
/*
Use CONTAINS to determine if the entry needs to be created.
Use the if's "then" clause to fetch the existing index or
"else" clause to create a new entry. The "t" loop has the
fastest speed on the first run, by far, and the slowest
speed on the second run.
*/
x2 = [=> ];
For( t = 1, t <= 2, t += 1,
start = HP Time();
For( ix = 1, ix < N, ix += 1,
If( Contains( x2, ix ),
y = x2[ix],
y = (x2[ix] = ix)
)
);
stop = HP Time();
Write( Eval Insert( "\!nContains method: ^char((stop - start)/1e6,5,3)^ seconds ^explain[t]^" ) );
);
/*
Use a DEFAULT value to determine if the entry needs to be
created. Fetch the value for the entry, check for the default
and create if needed. This gives an between value for both
"t" loops. It might be a good compromise choice if no extra
testing will be done and 0 can be used as a default. !y,
below, is faster than y==0.
*/
x3 = [=> 0];
For( t = 1, t <= 2, t += 1,
start = HP Time();
For( ix = 1, ix < N, ix += 1,
y = x3[ix];
If( !y, y = (x3[ix] = ix) );
);
stop = HP Time();
Write( Eval Insert( "\!ndefault 0 method: ^char((stop - start)/1e6,5,3)^ seconds ^explain[t]^" ) );
);
// quick test... the lack of a default value in x1 and x2
// makes them compare not equal, so add it before testing.
x1 << setdefaultvalue( 0 );
x2 << setdefaultvalue( 0 );
Show( x1 == x2, x1 == x3 );
尝试方法:2.851秒创建新条目
尝试方法: 0.099秒使用现有条目
包含方法: 0.209秒创建新条目
包含方法:0.151秒使用现有条目
默认0方法: 0.259秒创建新条目
默认0方法: 0.117秒使用现有条目
x1==x2=1;
x1==x3=1;
红色的 TRY 和 CONTAINS 提供现有条目和新条目的最快时间。 在绿色中,DEFAULT 0 可能是一个很好的折衷方案。 这实际上取决于将创建多少条目以及将查找它们多少次。
感谢您的提醒! 我在示例中选择了允许值集之外的默认值,因此作为默认值并没有多大用处。 零对于我的查找来说是无效的索引。 我从 Missing 开始,但是 isMissing(x) 比 x==0 更昂贵。
目前正在研究一些 REST API 的东西,因此关联数组和删除与默认值相同的键我已经/将避免使用默认值。 原因是我使用 JSON 响应为 JMP 用户构建交互式 UI,即使它们具有“默认值”,我也需要这些键。 但我想在这篇文章之后我将停止使用尝试检查丢失的密钥的惰性选项。
查看更多...