2012-01-14 6 views
3

이 문제가 있습니다. 빈 목록 (0 개 요소)에서 시작합니다.이 요소에 요소가 있거나 없는지 확인하고 싶습니다. 이 레코드가 목록에없는 경우 목록에이 레코드를 추가하고 그렇지 않으면 목록의 요소를 업데이트합니다. 이 코드 작성 시도 :List and Contains method

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. 

를하고이 결과를 반환해야합니다 :

10  2 
20  1 
30  1 
40  1 
50  1 

을하지만,이 결과를 반환은 :

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

나는 문제에 대해 이해 : 내가 oDBStats를 사용할 때 rDBStats 요소가 목록에 포함되어 있으면 제어합니다 (rDBStats). 처음으로 그것을 발견하지 못했고 목록에 추가; 하지만 그것이 목록에 추가되면 1로 freq 필드를 업데이트합니다; 그래서 내가 freq = 0 인 rdbstats를 다시 확인하면 두 번째로 발견되지 않습니다. 이 문제를 해결할 수 있습니까? 나는 "빗"이라는 입력을받는 카운터가 있어야하며,이 "빗"이 목록에 있는지, 다른 레코드 필드의 값에서 부주의하는지 확인하고 싶습니다. 내가 목록에서 "빗"을 찾으면, 나는 freq 필드를 증가시키면서 업데이트합니다. 도움 주셔서 감사합니다.

+0

임의로 선택한 유형 이름 때문에 코드를 읽기가 어렵습니다. 'TDBStats' 대신'TDBStatList'를 사용하고,'PDBStats' 대신'TDBStat'을 사용하십시오. – kludg

+0

완료되었으므로 도움이 되었기를 바랍니다. –

+0

'Freq' 필드 값은 또한'Contains' 메쏘드에서 테스트됩니다; rDBStats.Comb : = myArr [iIndex1]; 뒤에'rDBStats.Freq : = 1;'행을 추가하면 올바른 결과를 얻을 수 있지만 일반적인 해결책은 아닙니다. 당신은 당신의 목록에 대해 다른 비교자를 필요로합니다. – kludg

답변

6

Contains을 일반 목록에 호출하면 지정된 값이 이미 목록에 있는지 확인합니다. 귀하의 케이스에있는 값은 두 개의 필드로 구성된 레코드입니다. 맞춤 비교자를 지정하지 않았으므로 Delphi는 레코드의 경우 이진 비교를 수행하는 기본 비교자를 사용합니다.따라서 두 레코드가 이진수 인 경우에만 동등한 것으로 간주됩니다.

예제를 작동 시키려면 레코드의 빗 필드 만 비교하는 사용자 지정 비교자를 지정해야합니다. 다음은 예입니다.

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

또한 업데이트 루틴에 오류가 있습니다. 기존 값을 증가시키는 대신 item 매개 변수의 정의되지 않은 값을 증가시킵니다. 첫 줄의 변경으로 인해 작동하게됩니다.

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

정말 필요한 것은 dictionary이므로 잘못된 데이터 구조입니다.

목록을 사용할 때 근본적인 문제는 하위 집합 저장된 레코드로 검색하려고한다는 것입니다. 그러나 목록은 설정되지 않았습니다. TDictionary<Integer, Integer>을 사용하여 다시 쓰기하여 문제를 해결하십시오.

dictionary code example at the Embarcadero docwiki에 대한 철저한 읽기를 권유 할 수 있습니다.

comb이라고하는 것은 사전의 키이고 값은 freq입니다. 이 같은

var 
    Dict: TDictionary<Integer, Integer>; 

및 생성 :

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

나는 당신의 사전을 믿고있어이 같은 선언 :

Dict := TDictionary<Integer, Integer>; 

당신은 사전을 열거 할 수있는 항목을 추가하려면이 작업을 수행 단순한 for in 루프가 있습니다.

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

사전이 이상한 순서로 열거된다는 점에 유의하십시오. 인쇄하기 전에 정렬 할 수 있습니다.

사전에 각 항목과 관련된 자세한 정보를 저장하려면 추가 필드를 레코드에 넣으십시오.

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

그러면 사전이 TDictionary<Integer, TDictValue>이됩니다.

+0

제안 해 주셔서 감사합니다. 여기를 보았습니다. http://docwiki.embarcadero.com/CodeSamples/en/Generics_Collections_TDictionary_(Delphi)와 예를 들어 이해했습니다. 하지만 내 경우에는 할 수있는대로 이해해야 할 작은 문제가 있습니다. 특히, 그것을 선언하는 형식 섹션에서? 예를 들면 : TDBStatsList = TList 다음과 같이 써야합니다 : TDBStatsList = TDictionary ; 하지만 그것은 빗에서 오류가 발생합니다. 내가 잘 이해하면이 "빗"이 기본 키를 나타냅니다. 내가 더 잘 이해할 수있는 본보기를 줄 수 있습니까? sincerly 처음으로 내가 tdictionary를 사용합니다. 다시 한번 감사드립니다. –

+0

감사합니다. 방금 예를 읽었습니다. 나는 그것을 시험해 본다. 감사합니다. 대단히 감사합니다. –

+0

저는 두 필드를 사용하여 TDBStats 레코드를 단순화했습니다 : comb (기본 키로) 및 freq를 일반 필드로 사용하십시오. 실제 응용 프로그램에서이 레코드는이 필드가 요소 빗을 가져 오는 모든 시간에 업데이트되는 많은 필드로 구성됩니다. 귀하의 예제를 찾고 나는이 모든 필드를 추가해야합니다 : Dict.TryGetValue (빗, Freq, Field1, field2, fieldn) 같은 뭔가를 가지고 Dict.TryGetValue (빗, Freq)? 예제 코드를 가지고 나는 요소가 존재하는지 또는 Tdictionary를 사용하지 않는지 검사하는 부분 만 업데이트 할 수 있습니까? –