Domanda

ho questo problema:a partire da una lista vuota (0 elementi) voglio verificare se un elemento è presente o non presente in questo elenco.Nel caso In cui questo record non è presente nell'elenco, quindi aggiungo questo record alla lista, altrimenti aggiornamento elemento in elenco.Ho provato a scrivere questo codice:

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, System.Generics.Collections, System.Generics.Defaults;

type
  TDBStats = record
    Comb: Integer;
    Freq: Integer;
  end;
  TDBStatsList = TList<TDBStats>;

procedure Add(ODBStats: TDBStatsList; const Item: TDBStats);
var
  rItem: TDBStats;
begin
  rItem := Item;
  rItem.Freq := 1;
  oDBStats.Add(rItem);
end;

procedure Update(ODBStats: TDBStatsList; const Item: TDBStats; const Index: Integer);
var
  rItem: TDBStats;
begin
  rItem := Item;
  Inc(rItem.Freq);
  oDBStats[Index] := rItem;
end;


var
  oDBStats: TDBStatsList;
  rDBStats: TDBStats;
  myArr: array [0..4] of integer;
  iIndex1: Integer;
begin
  try
    myArr[0] := 10;
    myArr[1] := 20;
    myArr[2] := 30;
    myArr[3] := 40;
    myArr[4] := 10;

    oDBStats := TList<TDBStats>.Create;
    try
      for iIndex1 := 0 to 4 do
      begin
        rDBStats.Comb := myArr[iIndex1];
        if oDBStats.Contains(rDBStats) then
          Update(oDBStats, rDBStats, oDBStats.IndexOf(rDBStats))
        else
          Add(oDBStats, rDBStats);
      end;
      // Check List
      for iIndex1 := 0 to Pred(oDBStats.Count) do
        Writeln(oDBStats[iIndex1].Comb:3, oDBStats[iIndex1].Freq:10);
    finally
      oDBStats.Free;
    end;

  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

e dovrebbe tornare questo risultato:

10     2
20     1
30     1
40     1
50     1

ma restituisce questo risultato:

10     1
20     1
30     1
40     1
50     1
10     1

Ho capito il problema:quando uso oDBStats.Contiene(rDBStats) per il controllo di se rDBStats elemento è contenuto in una lista;il primo tempo non l'ha trovato e aggiungere in lista;ma quando viene aggiunto nella lista che aggiorno la freq campo 1;quindi secondo tempo quando posso controllare ancora una volta di essere rdbstats con freq = 0 non trovato.Come posso risolvere questo problema?Ho bisogno di avere un contatore, dove mi da l'input di un "pettine" e voglio verificare se questo "pettine" è presente nella lista, indipendetely dal valore di un altro campo del record.Nel caso In cui trovo "pettine" in lista, poi ho aggiornato i, aumentando la freq campo.Grazie per l'aiuto.

È stato utile?

Soluzione

Quando chiami Contains In un elenco generico, sembra se il valore dato è già all'interno dell'elenco. Il valore nel tuo caso è un record composto da due campi. Poiché non hai specificato un confronto personalizzato, Delphi utilizzerà un confronto predefinito che in caso di record esegue un confronto binario. Quindi solo quando due record sono uguali, saranno trattati come uguali.

Per far funzionare il tuo esempio devi specificare un confronto personalizzato che confronta solo il campo di pettine dei record. Questo è un esempio:

oDBStats := TList<TDBStats>.Create(TDelegatedComparer<TDBStats>.Create(
 function(const Left, Right: TDBStats): Integer
 begin
   result := CompareValue(Left.comb, Right.comb);
 end));

Inoltre, hai un errore nella routine di aggiornamento. Invece di incrementare il valore esistente, si sta incrementando il valore non definito del parametro elemento. La modifica nella prima riga dovrebbe farlo funzionare:

  rItem := oDBStats[Index];
  Inc(rItem.Freq);
  oDBStats[Index] := rItem;

Altri suggerimenti

Hai sbagliato i dati di struttura, in quanto ciò che si ha realmente bisogno è un dizionario.

Il problema fondamentale con l'utilizzo di un elenco che si desidera cercare in un sottoinsieme della stored record.Ma le liste non sono che.Risolvere il problema da ri-scrittura con TDictionary<Integer, Integer>.

Posso consigliare di avere un'approfondita lettura del dizionario esempio di codice all'Embarcadero docwiki.

La chiave per il dizionario è quello che si chiama comb e il valore è freq.Per aggiungere un elemento, questo:

if Dict.TryGetValue(Comb, Freq) then
  Dict[Comb] := Freq+1
else
  Dict.Add(Comb, 1);

Sto supponendo che il tuo dizionario è dichiarato come questo:

var
  Dict: TDictionary<Integer, Integer>;

e creato come questo:

Dict := TDictionary<Integer, Integer>;

È possibile enumerare il dizionario con un semplice for in loop.

var
  Item: TPair<Integer, Integer>;
...
  for Item in Dict do
    Writeln(Item.Key:3, Item.Value:10);

Anche se ha avvertito che il dizionario verrà enumerare in uno strano ordine.Si possono ordinare prima della stampa.

Se si desidera memorizzare più informazioni associate ad ogni voce del dizionario poi mettere le ulteriori campi di un record.

type
  TDictValue = record
    Freq: Integer;
    Field1: string;
    Field2: TDateTime;
    //etc.
  end;

Quindi il tuo dizionario è TDictionary<Integer, TDictValue>.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top