[英]count unique values in array
我很难计算数组中唯一值的数量。 我不能真正使用 [i+1] 来评估,因为它可能会将第 i+1 个 position 之后的任何值计算为唯一值,而实际上稍后在数组中有重复值(参见 28 和 29)...任何想法? 非常感谢您的帮助!
[28, 28, 29, 30, 01, 28, 02, 29]
function CalcDiscretePeriods(const Arr: Array):Integer;
var
i: Integer;
begin
for i:= 0 to High(Arr)-1 do
begin
if (Arr[i]<>Arr[i+1]) then countD:= countD + 1;
end;
end;
(我正在使用 MacOSX,免费的 Pascal 编译器版本 2.6.4 [2014/02/26] for i386 如果相关的话)。
根据个人经验,您可以使用以下算法来成功计算数组中的唯一值。
您将需要第二个数组,例如“ uniqueArray”(理想的是像数据结构这样的哈希图比数组要好)
1)从现有数组'Arr'中的每个元素'i'从i = 0迭代到High(Arr)-1
2)对于每个“ i”, 仅当 uniqueArr尚未具有该值时,才将此值复制到第二个数组“ uniqueArray”中(需要uniqueArr中每个元素的循环)。
3)成功复制后,增加计数。
恐怕我不熟悉提供任何实际示例的语言。
一个特别慢但 memory 有效的方法是遍历数组两次。 以下是符合 Extended Pascal(ISO 标准 10206)的摘录:
type
integerNonNegative = 0..maxInt;
{ returns the number of unique values in `list` }
function discretePeriods(
protected list: array[lowerBound..upperBound: integer] of integer
): integerNonNegative;
{ determines whether `reference` occurs only once in `list` }
function isUnique(protected reference: type of list[lowerBound]): Boolean;
{ counts the number of occurences of a `reference` value }
function occurences: integerNonNegative;
var
i: type of lowerBound;
n: integerNonNegative value 0;
begin
for i := lowerBound to upperBound do
begin
if list[i] = reference then
begin
n := n + 1;
end;
end;
occurences := n;
end;
begin
isUnique := occurences = 1;
end;
var
i: type of lowerBound;
uniqueValues: integerNonNegative value 0;
begin
for i := lowerBound to upperBound do
begin
if isUnique(list[i]) then
begin
uniqueValues := uniqueValues + 1;
end;
end;
discretePeriods := uniqueValues;
end;
另一种更快但内存密集型的方法是,正如已经建议的那样,将分析步骤与计算步骤分开。 在 Extended Pascal 中,这可能如下所示:
const
integersMaximum = 4194303;
type
integerNonNegative = 0..maxInt;
integersRange = -integersMaximum..+integersMaximum;
{$setLimit=8388608}{ only in GPC }
integers = set of integersRange value [];
{ returns the number of unique values in `list` }
function discretePeriods(
protected list: array[lowerBound..upperBound: integer] of integersRange
): integerNonNegative;
var
population: integers;
procedure populate;
var
i: type of lowerBound;
begin
{ transform ordered list to “unordered” `set` }
for i := lowerBound to upperBound do
begin
population := population + [list[i]];
end;
end;
function duplicates: integers;
var
i: type of lowerBound;
m: integers;
begin
for i := lowerBound to upperBound do
begin
{ construct a set of all values that appear more than once }
if not (list[i] in population) then
begin
m := m + [list[i]];
end;
{ at any rate remove the current item from `population` }
population := population - [list[i]];
end;
duplicates := m;
end;
var
n: integerNonNegative;
begin
populate;
{ calculation step }
n := card(population);
discretePeriods := n - card(duplicates);
end;
最后还是要看你的具体使用场景。 可能您(最终)无论如何都需要对数组进行排序,因此Rudy Velthuis建议的方法可能最适合您。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.