我有这个文件:
Bulgaria = Bulgarian
Croatia = Croatian
Austria = Croatian
Czech Republic = Czech
Slovakia = Czech
Denmark = Danish
Germany = Danish
Belgium = Dutch
Netherlands = Dutch
Ireland = English
Malta = English
United Kingdom = English
Estonia = Estonian
Finland = Finnish
Belgium = French
France = French
Italy = French
Luxembourg = French
Austria = German
Belgium = German
Denmark = German
Germany = German
Italy = German
Luxembourg = German
Cyprus = Greek
Greece = Greek
Austria = Hungarian
Hungary = Hungarian
Romania = Hungarian
Slovakia = Hungarian
Slovenia = Hungarian
Ireland = Irish
United Kingdom = Irish
Croatia = Italian
Italy = Italian
Slovenia = Italian
Latvia = Latvian
Lithuania = Lithuanian
Malta = Maltese
Poland = Polish
Portugal = Portuguese
Romania = Romanian
Slovakia = Slovak
Czech Republic = Slovak
Hungary = Slovak
Slovenia = Slovenian
Austria = Slovenian
Hungary = Slovenian
Italy = Slovenian
Spain = Spanish
Sweden = Swedish
Finland = Swedish
在python中,我使用此代码创建一个关联数组,其中字符串为键,数组为值:
from collections import defaultdict
mydata = defaultdict(list)
myfile = open("myfile", "r")
for line in myfile:
country, language = line.rstrip('\n').split(" = ")
mydata[country].append(language)
它创建了一个这样的数据结构:
'Bulgaria' = ['Bulgarian']
'Croatia' = ['Croatian']
'Austria' = ['Croatian', 'German', 'Hungarian', 'Slovenian']
# and so on
Perl和Ruby有类似的关联数组。 Go可以使用地图和append()
创建它。
我在Pascal中看到很多对关联数组的引用,但我找不到使用数组作为值的示例。
我正在使用FreePascal,我想避免使用外部库。你能告诉我一个例子吗?。
PS:我知道这看起来像是家庭作业,但事实并非如此。
答案 0 :(得分:5)
Pascal(Delphi)语言在该语言中没有关联数组。只有具有序数类型索引的数组(即整数,不是字符串或浮点数)。有多维数组,最近还有动态数组,但索引无论如何都是有序的。
但是,标准库单元(Classes.pas和System.Generics.Collections.pas)提供了实现您所说功能的类。
您可以将新的Delphi Generics(特别是TDictionary)用于真正的关联数组,或者使用旧的TStringList,仅用于纯字符串列表。在较新版本的Delphi中,TStringList类已使用Name + Delimiter + Value功能进行了扩展。对于这些对,TStringList比Delphi Generics的TDictionary慢,因为它只是存储普通字符串并在运行中解析它们。但是,泛型使用高效的结构,可以快速添加和删除项目,使用值的哈希值,因此速度非常快。相反,在TStringList中,随机插入和删除很慢 - O(N),但是通过索引获取字符串是瞬间的 - O(1)。
uses
System.Generics.Collections,
procedure TestGenerics;
type
TKey = string;
TValue = string;
TKeyValuePair = TPair<TKey, TValue>;
TStringDictionary = TDictionary<TKey, TValue>;
var
D: TStringDictionary;
K: TKey;
V: TValue;
P: TKeyValuePair;
ContainsKey, ContainsValue: Boolean;
begin
D := TStringDictionary.Create;
D.Add('Bulgaria', 'Bulgarian');
D.Add('Croatia', 'Croatian Italian');
K := D.Items['Bulgaria'];
P := D.ExtractPair('Bulgaria');
ContainsKey := D.ContainsKey('Bultaria');
ContainsValue := D.ContainsValue('Bultarian');
// you do not need to free P, since it is just a record in the stack
D.Free;
end;
请注意,Delphi的作者称之为Name + Value对,而不是Key + Value对,因为在TStringList中,这些实际上并不是&#34; Keys&#34;在快速访问方式中,它只是同一个字符串的一部分。他们没有特殊的排序索引功能 - 如果您愿意,只需定期排序的TStringList。
另请注意,当TStringList对象包含名称 - 值对或名称的字符串时,请读取键以访问字符串的名称部分。如果字符串不是名称 - 值对,则Keys返回完整字符串。分配键将为名称 - 值对写入新名称。这与Names属性形成对比。
另外,请注意,TStringList使用连续的内存空间来保存指向字符串数据的指针,因此当您添加新字符串时,它会使用预先分配的空间来存储更多条目,但随后会分配一个新的更大内存阻止并将旧指针复制到新指针,释放旧块。所以,如果事先知道了项目的数量,最好将该数字告诉TStringList,它会一次性预分配缓冲区。如果您需要更多项目,这不会阻止以后扩大缓冲区。
uses
Classes;
procedure TestStringList;
var
SL: TStringList;
FullString, Separator, FName, FValue: string;
begin
SL := TStringList.Create;
SL.AddPair('Bulgaria', 'Bulgarian'); // add a Name -> Value pair
SL.AddPair('Croatia', 'Croatian Italian');
// Names and KeyNames is the same
FName := SL.Names[0]; // Indicates the name part of strings that are name-value pairs.
FName := SL.KeyNames[0];
FValue := SL.Values['Bulgaria']; // Represents the value part of a string associated with a given name, on strings that are name-value pairs.
FValue := SL.ValueFromIndex[0]; // Represents the value part of a string with a given index, on strings that are name-value pairs.
FullString := SL.Strings[0]; // References the strings in the list by their positions (the whole Name+Separator+Value pair)
Separator := SL.NameValueSeparator; // Indicates the character used to separate names from values.
SL.Free;
end;
答案 1 :(得分:4)
接下来是一个演示程序。
打开Lazarus,创建一个Application,并将单元fgl
添加到单元的uses子句中:
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, fgl;
在表单中添加TButton(Button1)和TMemo(Memo1),并为该按钮提供以下代码:
{ Can't find anything suitable in the Lazarus runtime. I'm sure this }
{ can be improved. }
function Strip(const S: string): string;
var
left, right: Integer;
begin
if S = '' then
begin
Result := S;
Exit;
end;
left := 1;
while S[left] in [' ', #9] do
Inc(left);
right := Length(S);
while (right > 0) and (S[right] in [' ', #9]) do
Dec(right);
Result := Copy(S, left, right - left + 1);
end;
type
TMap = specialize TFPGMap<string, TStringList>;
procedure TAssocForm.Button1Click(Sender: TObject);
var
mydata: TMap;
myfile: Text;
line: string;
country: string;
language: string;
mypos: Integer;
SL: TStringList;
I: Integer;
begin
{ Error handling needs to be added, e.g. if file doesn't exist, or if
a line doesn't contain an =, etc. etc. }
mydata := TMap.Create;
{ Open file 'myfile.txt' for reading. }
System.Assign(myfile, '/Users/xxx/yyy/myfile.txt'); { adjust accordingly }
Reset(myfile);
{ Read lines. }
while not Eof(myfile) do
begin
Readln(myfile, line);
mypos := Pos('=', line);
{ Split line into country and language. }
country := Strip(Copy(line, 1, mypos - 1));
language := Strip(Copy(line, mypos + 1, MaxInt));
{ If key not present yet, add a new string list. }
if mydata.IndexOf(country) < 0 then
mydata.Add(country, TStringList.Create);
{ add language to string list of country. }
mydata[country].Add(language);
end;
System.Close(myfile);
Memo1.Lines.Clear;
Memo1.Lines.BeginUpdate;
for I := 0 to mydata.Count - 1 do
begin
{ Get key. }
country := mydata.Keys[I];
line := country + ' -> ';
{ Get string list. }
SL := mydata[country];
{ Get languages in the string list. }
for language in SL do
line := line + language + ' ';
{ Add line to memo. }
Memo1.Lines.Add(Strip(line));
end;
Memo1.Lines.EndUpdate;
{ Free the string lists. }
for I := 0 to mydata.Count - 1 do
mydata[mydata.Keys[I]].Free;
end;
end.
运行程序并单击按钮。备忘录将填写国家和那里所说的语言,例如:
Bulgaria -> Bulgarian
Croatia -> Croatian Italian
Austria -> Croatian German Hungarian Slovenian
Czech Republic -> Czech Slovak
Slovakia -> Czech Hungarian Slovak
etc...