【问题标题】:Delphi extract key from TObjectDictionaryDelphi 从 TObjectDictionary 中提取密钥
【发布时间】:2011-08-17 11:52:31
【问题描述】:

分享这个问题的代码作为参考:Delphi TPair Exception

如何在不使用 TPair 且不从列表中提取/删除/删除该对的情况下从 TObjectDictionary 具体条目中检索键和值?

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Generics.Defaults,
  Generics.Collections;

type
  TProduct = class
  private
    FName: string;
    procedure SetName(const Value: string);
  published
  public
    property Name: string read FName write SetName;
  end;

type
  TListOfProducts = TObjectDictionary<TProduct, Integer>;

{ TProduct }

procedure TProduct.SetName(const Value: string);
begin
  FName := Value;
end;


var
  MyDict: TListOfProducts;
  MyProduct1: TProduct;
  MyProduct2: TProduct;
  MyProduct3: TProduct;
  APair: TPair<TProduct, Integer>;
  aKey: string;

begin
  try
    MyDict := TListOfProducts.Create([doOwnsKeys]);
    MyProduct1 := TProduct.Create;
    MyProduct1.Name := 'P1';
    MyProduct2 := TProduct.Create;
    MyProduct2.Name := 'P2';
    MyProduct3 := TProduct.Create;
    MyProduct3.Name := 'P3';

    MyDict.Add(MyProduct1, 1);
    MyDict.Add(MyProduct2, 2);
    MyDict.Add(MyProduct3, 3);

    //the code to look for a **concrete product** (ie: MyProduct1) goes here..

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

谢谢。

===========================

= 带有答案的代码 =

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Generics.Defaults,
  Generics.Collections;

type
  TProduct = class
  private
    FName: string;
    procedure SetName(const Value: string);
  published
  public
    property Name: string read FName write SetName;
  end;

type
  TListOfProducts = TObjectDictionary<TProduct, Integer>;

{ TProduct }

procedure TProduct.SetName(const Value: string);
begin
  FName := Value;
end;


var
  MyDict: TListOfProducts;
  MyProduct1: TProduct;
  MyProduct2: TProduct;
  MyProduct3: TProduct;

  MySearchedProduct: TProduct;   // From Answer.

  APair: TPair<TProduct, Integer>;
  aProductName: string;

begin
  try
    MyDict := TListOfProducts.Create([doOwnsKeys]);
    MyProduct1 := TProduct.Create;
    MyProduct1.Name := 'P1';
    MyProduct2 := TProduct.Create;
    MyProduct2.Name := 'P2';
    MyProduct3 := TProduct.Create;
    MyProduct3.Name := 'P3';

    MyDict.Add(MyProduct1, 1);
    MyDict.Add(MyProduct2, 2);
    MyDict.Add(MyProduct3, 3);

    Writeln('Enter the Product Name to search: ');

    //the code to look for a **concrete product** goes here..
    Readln(aProductName);
    for MySearchedProduct in Mydict.Keys do
      if (MySearchedProduct.Name = aProductName) then
        break;
    if MySearchedProduct.Name = aProductName then
      WriteLn('I have found the product: ' + MySearchedProduct.Name)
    else
      WriteLn('I have not found a product with that name.');

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

【问题讨论】:

  • @RRUZ Gracias por la edición de la pregunta。感谢您对问题的编辑。我认为最好不要重复几乎相同的代码,但我认为最好在此处单独维护它。
  • 两件事:(1)你忽略了编译器警告,不要那样做。如果字典不包含任何内容,则不会定义 for 循环变量 (MySearchedProduct),从而导致 AV。 (2) 如果您需要按名称搜索产品,请使用TDictionary&lt;string, Product&gt;TList&lt;Product&gt;。字典不应该用于顺序访问,而是用于基于键的快速搜索。如果您需要顺序访问,请使用TList&lt;T&gt;TObjectList&lt;T&gt;
  • @Cosmin-Prund 是的,我知道如果列表中没有任何内容,MySearchedProduct 将是 nil。谢谢... 我不需要按名称搜索产品,这只是一个示例代码。我需要根据产品的任何属性、功能以及可能同时在其中的几个中搜索产品。因此,我需要完整的对象,因为搜索将超过可变数量的elements。感谢您的约会... :-)

标签: delphi generics vcl delphi-xe


【解决方案1】:

如果您的字典包含大量成员,则遍历键可能会非常缓慢。我建议将密钥与实际值一起保留在 Pair 中。考虑到提供的示例,它可能如下所示:

type
 TListOfProducts = TObjectDictionary<TProduct, TPair<TProduct,Integer>>;

【讨论】:

    【解决方案2】:

    KeyValue 在字典中保存为 TPair&lt;TKey,TValue&gt;。如果您需要同时使用键和值,那么合乎逻辑的做法是使用TPair;

    看起来像这样:

    for APair in MyDict do
    begin
      // Your stuff goes here.
    end;
    

    如果由于某种原因您不想使用 TPair 来提取对,您可以使用类似的方法,但这绝对不是一个好主意 - 您无缘无故地进行大量字典查询:

    for AKey in MyDict.Keys do
    begin
      AValue := MyDict[AKey];
      // Do something with both AKey and AValue
    end;
    

    【讨论】:

    • 很高兴看到for Apair in MyDict do 运行良好(我已经测试过了)。因为 MyDict.ExtractPair 没有像您在链接问题中看到的那样运行作为参考(在原始问题中)。为你 +1。
    • @FerPt 您是否了解我在上一个问题中概述的 ExtractPair 修复?
    • Hummmm...如果您提到手动编辑VCL源代码,请将DoRemove(Key, hc, cnExtracted);更改为result := DoRemove(Key, hc, cnExtracted);我宁愿不要这样做。任何更新、服务包或新安装都将破坏所有工作。如果有任何替代方法而无需“从其他人”修改代码,我更喜欢它。无论如何,谢谢大卫......
    • @Downvoter,在 3 个不同的问题上,彼此在几秒钟内投了 3 次反对票?我认为问为什么是徒劳的。
    • @FerPt,如果您查看每个问题和答案的侧面,您会看到一个带有两个箭头(向上和向下)的数字。例如,在撰写本文时,您的问题得分为 4:它得到了 4 个“赞成票”。同时,我的回答得到 1 票赞成和 1 票反对,得分为“0”。从理论上讲,否决票正是向下箭头上的工具提示所说的:它将答案标记为“无用”。不幸的是,人们滥用系统并出于各种其他原因(政治、个人关系和最糟糕的)投票。您应该阅读该网站的常见问题解答,因为投票是 SO 工作方式的重要组成部分
    【解决方案3】:

    您可以使用 MyDict 的 KeysValues 属性。

    在这样的循环中:

    var
      MyProduct: TProduct;
      Value: Integer;
    begin
    
      for Value in MyDict.Values do
        writeln(Value);
    
      for MyProduct in MyDict.Keys do
        writeln(MyProduct.Name);
    

    或者通过索引使用ToArray:

    writeln(MyDict.Keys.ToArray[1].Name);
    writeln(MyDict.Values.ToArray[1]);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-28
      • 2012-07-13
      • 2023-03-14
      • 1970-01-01
      • 2014-10-21
      • 1970-01-01
      相关资源
      最近更新 更多