2010-10-23 27 views
5

Me gustaría tener un diccionario que devuelve un valor predeterminado cuando no se encuentra la clave de búsqueda. Lectura de la documentación:Delphi Generics> Diccionario con valor predeterminado

Generics.Collections.Tdictionary [...] Esta clase proporciona [...] un mapeo y contenido inicial.

1 - ¿Cómo? ¿Hay alguna manera de hacerlo en Python: {1: 'uno'; 2: 'dos'}?

Generics.Collections.TDictionary.TryGetValue [...] TryGetValue devuelve verdadero si la clave dada está en el diccionario y proporciona su valor en Valor. De lo contrario, devuelve falso y Value se establece en el tipo de valor predeterminado de Tvalue.

2 - ¿Cómo puedo establecer este valor predeterminado? No puedo encontrar un constructor (puede ser que acabo de buscar en el lugar equivocado. Estoy esperando algo como "constructor Create (DefaultValue: TValue);")

Así que estoy tratando de implementar mi propio (puede ser que no es necesario Véase más arriba.): (comentarios y sugerencias son bienvenidos)

El código es:

unit Util; 

interface 

uses 
    Generics.collections; 

type 

    // 
    // Dictionary with default response 
    // 
    TDefaultDictonary<K, V> = class(TObjectDictionary<K, V>) 
    private 
     M_DefaultValue : V; 

    public 
     constructor Create(Defaultvalue : V); 
     destructor Destroy; reintroduce; 
     function GetDefaultValue : V; 
     function TryGetValue(const Key: K; out Value: V): Boolean; 
     function GetValueOf(const Key: K) : V; 
    end; 

implementation 

// 
// Contructor and destructor 
// 
constructor TDefaultDictonary<K, V>.Create(Defaultvalue : V); 
begin 
    inherited Create; 

    M_DefaultValue := Defaultvalue; 
end; 

destructor TDefaultDictonary<K, V>.Destroy; 
begin 
    inherited Destroy; 
end; 

// 
// Get the default Value 
// 
function TDefaultDictonary<K, V>.GetDefaultValue : V; 
begin 
    Result := M_DefaultValue; 
end; 


// 
// Try to get a value from the dictionary for the given key. 
// 
// If the value is found then "Value" holds it and the function returns true. 
// If the value is not found then "Value" holds the default value and the 
// function returns false. 
// 
function TDefaultDictonary<K, V>.TryGetValue(const Key: K; out Value: V): Boolean; 
var 
    IsKeyFound : boolean; 
    DictVal : V; 

begin 
    IsKeyFound := inherited TryGetValue(Key, DictVal); 
    if not IsKeyFound then begin 
     DictVal := M_DefaultValue; 
    end; 

    // Outputs: 
    Value := DictVal; 
    Result := IsKeyFound; 
end; 


// 
// Get a value from the dictionary for the given key. 
// 
// If the value is found then the function returns it. 
// If the value is not found the function returns the default value. 
// 
function TDefaultDictonary<K, V>.GetValueOf(const Key: K) : V; 
var 
    DictVal : V; 

begin 
    TryGetValue(Key, DictVal); 

    Result := DictVal; 
end; 

y las pruebas son:

unit Test_Utils; 
{ 
    Test the TDefaultDictionary functionality 
} 

interface 

uses 
    Sysutils, Math, TestFramework, Util; 

type 

    TestUtil = class(TTestCase) 

    public 
     procedure SetUp; override; 
     procedure TearDown; override; 

    published 
     procedure TestDefaultDictionaryGetDefaultResponse; 
     procedure TestDefaultDictionaryExistingKey; 
     procedure TestDefaultDictionaryNotExistingKey; 

    end; 


implementation 


procedure TestUtil.SetUp; 
begin 
end; 

procedure TestUtil.TearDown; 
begin 
end; 


procedure TestUtil.TestDefaultDictionaryGetDefaultResponse; 
var 
    dd : TDefaultDictonary<integer, string>; 

begin 
    dd := TDefaultDictonary<integer, string>.Create('Default response'); 
    checkEquals('Default response', dd.GetDefaultValue); 

    dd.Free; 
end; 

procedure TestUtil.TestDefaultDictionaryExistingKey; 
var 
    dd : TDefaultDictonary<integer, string>; 
    outVal : string; 
    isKeyFound : boolean; 

begin 
    dd := TDefaultDictonary<integer, string>.Create('Default response'); 
    dd.Add(1, 'My one'); 

    checkEquals(1, dd.Count, 
     'One element as count'); 

    isKeyFound := dd.TryGetValue(1, outVal); 
    check(isKeyFound, 
     'Key not found by TryGetValue'); 

    checkEquals('My one', outVal, 
     'Value given by TryGetValue'); 

    checkEquals('My one', dd[1], 
     'Value given by indexing as array'); 

    dd.Free; 
end; 


procedure TestUtil.TestDefaultDictionaryNotExistingKey; 
var 
    dd : TDefaultDictonary<integer, string>; 
    outVal : string; 
    isKeyFound : boolean; 

begin 
    dd := TDefaultDictonary<integer, string>.Create('Default response'); 
    dd.Add(1, 'one'); 

    isKeyFound := dd.TryGetValue(2, outVal); 
    check(not isKeyFound, 
     'Key should not be found by TryGetValue'); 

    checkEquals('Default response', outVal, 
     'Default Value given by TryGetValue'); 

    checkEquals('Default response', dd.GetValueOf(2), 
     'Default Value given by indexing as array'); 

    // 
    // It is possible to oveload the indexer operator? 
    // Please review or delete me ! 
    // 
    //checkEquals('Default response', dd[2], 
    //  'Value given by indexing as array'); 
    // 

    dd.Free; 
end; 


initialization 
    RegisterTest(TestUtil.Suite); 
end. 

eso está lejos de siendo completo. Me gustaría que el operador del indexador también funcione (ver la última prueba). Es así de posible? ¿Qué debería también implementarse?

¿Esta implementación se filtra M_DefaultValue (soy nuevo en Delphi). No puedo hacer algo M_DefaultValue.Free en el destructor (no es tan flexible debido a la restricción del constructor) ¿Qué se puede hacer aquí?

Gracias de antemano,

Francis

+0

Ha planteado una muy buena pregunta, ya que actualmente, en Delphi, tenemos que hacer dos búsquedas en el diccionario. Lo mismo es cierto acerca de PHP. –

Respuesta

1

Antes de escribir todo este código usted mismo, es posible que desee ver en las clases genéricas en el DeHL library.

Es compatible con esto:

Tipo concepto de apoyo que define un conjunto de clases de apoyo "por defecto" para cada tipos incorporados Delphi (usados ​​como defecto en colecciones). Se pueden registrar clases personalizadas de "tipo support" para sus tipos de datos personalizados.

--jeroen

+0

Espero que sea algo diferente: comparadores predeterminados y similares, no un valor predeterminado devuelto por un diccionario en el caso de "clave no presente". –

+0

Su respuesta no es tan amistosa. La idea principal de la pregunta del autor era evitar dos búsquedas: la primera búsqueda no es verificar si el valor existe, y la segunda búsqueda para devolver realmente el valor. Si hubiera proporcionado una respuesta clara y directa, con un ejemplo de código, esto hubiera sido útil, por ejemplo, sobre cómo usar TryGetValue y que cada tipo tiene un valor predeterminado que no se puede cambiar, por ejemplo, Integer tiene 0, la cadena tiene '', etc. –

+0

@MaximMasiutin, ya que el usuario Francisco nunca respondió (la última vez que estuvo activo en 2010) y planteó un puñado de preguntas en una sola pregunta, es difícil entender cuál es su tropezón. Entonces, dado el estado del código en la pregunta, asumí que escribir un buen código de biblioteca estable era el principal problema y dirigirme a la biblioteca de DeHL - entonces actual. Hoy en día dirigiría a http://spring4d.org –

0

El principal problema es GetItem no es virtual en TDictionary <>. Esto se puede resolver con sólo añadir

property Items[const Key: K]: V read GetValueOf write SetItem; default; 

a su clase.

Btw, los destructores deben ser modificados, no reintroducidos por lo que cuando lo almacena en una variable definida como clase de jerarquía superior llama al destructor derecho. Esa es solo una mejor práctica, pero en este caso específico Items [] no funcionaría como usted quisiera si lo hiciera.

Dios te bendiga.

Cuestiones relacionadas