повторение словаря Delphi - PullRequest
1 голос
/ 07 апреля 2011

g'morning!

Я заполняю словарь TDictionary<String, TStringlist> (delphi-collection-unit) строками в качестве значений и несколькими строками в качестве значений.что-то вроде:

  • Имена = Джон, Лиза, Стан
  • навыки = читать, писать, говорить
  • возраст = 12, 14, 16

(без "," конечно).что мне нужно, это перебрать этот словарь и умножить значения с ключами.выходные данные должны выглядеть следующим образом:

  • names = john навыков = возраст чтения = 12
  • names = john skill = возраст чтения = 14
  • names = john skill = чтение возраста= 16
  • Имена = Навыки Джона = Возраст записи = 12
  • Имена = Навыки Джона = Возраст записи = 14
  • Имена = Навыки Джона = Возраст записи = 16
  • ...
  • имена = навыки Лизы = возраст чтения = 12
  • ...
  • имена = навыки стэна = возраст разговора = 16

так что каждая комбинация.как я могу это сделать?количество ключей является динамическим, как и размер списка строк.Спасибо!К настоящему времени решено ...

Теперь проблема с объемом.Ниже приведена процедура, которая заполняет диктат.subsplits и splitstring являются строковыми списками, которые освобождаются в конце процедуры.dict создается после блока процедур (в основном? как он называется?), вызывается метод fill, а затем я хочу выполнить рекурсию, как в примере кода, но в dict нет значений ....

while not Eof(testfile) do
  begin
    ReadLn(testfile, text);
    if AnsiContainsStr(text, '=') then
    begin
      Split('=', text, splitarray);
      splitarray[0] := trim(splitarray[0]);
      splitarray[1] := DeleteSpaces(splitarray[1]);
      if AnsiStartsStr('data', splitarray[0]) then
      begin
        split(' ', splitarray[0], subsplit1);
        splitarray[0]:=subsplit1[1];
        split(',', splitarray[1], subsplit2);
        dict.Add(splitarray[0], subsplit2);
        for ValueName in dict.Values do
        begin
          for i := 0 to Valuename.Count - 1 do
          write('Values are : '+ Valuename[i]);
        writeln;
        end;//
      end;//
    end;//
  end;//

1 Ответ

6 голосов
/ 07 апреля 2011

То, что вы хотите, немного усложняется использованием TDictionary<string, TStringList>, потому что это подразумевает переменное количество ключей.Если бы не переменное количество ключей, вам не понадобился бы словарь, и вы бы просто перебрали 3 TStringLists.

Тем не менее, у вас есть классическая проблема "генерировать все перестановки",Это можно решить с помощью рекурсии или возврата .Рекурсия проще в реализации, для возврата требуется меньше места в стеке.Выбор за вами.Вот полное консольное приложение, которое выполняет всю работу: от инициализации словаря, заполнения словаря до генерации всех перестановок с использованием рекурсивной функции.

program Project23;

{$APPTYPE CONSOLE}

uses
  SysUtils, Classes, Generics.Collections;

var
  Dict:TDictionary<string, TStringList>;
  L: TStringList;
  KeyName: string;
  KeysList: TStringList;

// Help procedure, adds a bunch of values to a "Key" in the dictionary
procedure QuickAddToDict(KeyName:string; values: array of string);
var L: TStringList;
    s: string;
begin
  // Try to get the TStringList from the dictionary. If we can't get it
  // we'll create a new one and add it to the dictionary
  if not Dict.TryGetValue(KeyName, L) then
  begin
    L := TStringList.Create;
    Dict.Add(KeyName, L);
  end;
  // Iterate over the values array and add stuff to the TStringList
  for s in values do
    L.Add(s);
end;

// Recursive routine to handle one KEY in the dictionary
procedure HandleOneKey(KeyIndex:Integer; PrevKeys:string);
var L:TStringList;
    i:Integer;
    Part: string;
    KeyName: string;
begin
  KeyName := KeysList[KeyIndex];
  L := Dict[KeyName];
  for i:=0 to L.Count-1 do
  begin
    Part := KeyName + '=' + L[i];
    if KeyIndex = (KeysList.Count-1) then
      WriteLn(PrevKeys + ' ' + Part) // This is a solution, we're at the last key
    else
      HandleOneKey(KeyIndex+1, PrevKeys + ' ' + Part); // Not at the last key, recursive call for the next key
  end;
end;

begin
  try
    Dict := TDictionary<string, TStringList>.Create;
    try

      // Add whatever you want to the Dict.
      // Using the helper routine to set up the dictionary faster.
      QuickAddToDict('names', ['john', 'lisa', 'stan']);
      QuickAddToDict('skills', ['read', 'write', 'speak']);
      QuickAddToDict('ages', ['12', '14', '16']);

      // Extract all the keys to a string list. Unfortunately the dictionary
      // doesn't offer a way to get a key name by index, so we have to use the
      // keys iterator to extract all keys first.
      KeysList := TStringList.Create;
      try
        for KeyName in Dict.Keys do
          KeysList.Add(KeyName);
        if KeysList.Count > 0 then
        begin
          // We got at least one key, we can start the recursive process.
          HandleOneKey(0, '');
        end;
      finally KeysList.Free;
      end;

      WriteLn;
      WriteLn('Press ENTER to make the window go away');
      ReadLn;

    finally
      // TDictionary doesn't own the keys or the values. Strings are managed types in
      // delphi, we don't need to worry about them, but we do need to free the TStringList's
      // We use the Values iterator for that!
      for L in Dict.Values do
        L.Free;
      Dict.Free;
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
...