Toon posts:

[C#] Dictionary met index functie als list

Pagina: 1
Acties:

Verwijderd

Topicstarter
Hi,

Op dit moment maak ik gebruik van een Dictionary type. Dit was voorheen een List, maar aangezien een List niet een functie heeft waarbij je een element kan opvragen aan de hand van een key, is het een Dictionary type geworden.

Om het toch mogelijk te maken om op een index gegevens uit te kunnen lezen itereer ik door de dictionary:
C#:
186
187
188
189
190
191
192
193
194
195
196
int intIndexCounter = 0;
/// Walk through the dictionary to find the index
foreach (KeyValuePair<int, T> objCacheStruct in objCacheDictionary)
{
  /// Index is found, return the cache object by ID
  if (intIndexCounter == intpIndex)
  {
    return ReturnById(objCacheStruct.Key);
  }
  intIndexCounter++;
}

Heeft iemand enig idee hoe dit effectief veranderd kan worden? Zelf dacht ik aan het extenden van een List met IDictionary type zodat de List functionaliteit qua het rechtstreeks aanroepen mogelijk is en via de IDictionary de key mechanisme...

Andere suggesties zijn uiteraard ook welkom.

Statix

[ Voor 3% gewijzigd door Verwijderd op 20-11-2006 14:31 ]


  • whoami
  • Registratie: December 2000
  • Laatst online: 18:04
Ik begrijp je code niet goed, waar wordt intpIndex gedeclareerd, en hoe kom je aan de waarde van intpIndex ?

Bedoel je nu dat je een soort van structuur wilt hebben waarbij je zowel op Index als op Key kunt zoeken ?
Indien dit het geval is, kijk dan eens naar de NameObjectCollectionBase class.
Zorg er dan voor dat je de Indexer die een string en de indexer die een int neemt, implementeert.

Ik weet ook niet zo direct of er in .NET 2.0 een generic variant is voor die class.

[ Voor 23% gewijzigd door whoami op 20-11-2006 14:39 ]

https://fgheysels.github.io/


Verwijderd

Topicstarter
whoami schreef op maandag 20 november 2006 @ 14:38:
Ik begrijp je code niet goed, waar wordt intpIndex gedeclareerd, en hoe kom je aan de waarde van intpIndex ?

Bedoel je nu dat je een soort van structuur wilt hebben waarbij je zowel op Index als op Key kunt zoeken ?
Indien dit het geval is, kijk dan eens naar de NameObjectCollectionBase class.
Zorg er dan voor dat je de Indexer die een string en de indexer die een int neemt, implementeert.

Ik weet ook niet zo direct of er in .NET 2.0 een generic variant is voor die class.
Dit is de complete functie
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/// <summary>
/// Get a cached object at a certain index
/// </summary>
/// <param name="intpIndex">Index</param>
/// <returns>Cached object</returns>
public T Return(int intpIndex)
{
    if (intpIndex == objCacheDictionary.Count)
    ////if the index is passed the last entry then return a empty instance
    {
        return default(T);
    }
    /// Find the cached object for the given index
    else
    {
        int intIndexCounter = 0;
        /// Walk through the dictionary to find the index
        foreach (KeyValuePair<int, T> objCacheStruct in objCacheDictionary)
        {
            /// Index is found, return the cache object by ID
            if (intIndexCounter == intpIndex)
            {
                return ReturnById(objCacheStruct.Key);
            }
            intIndexCounter++;
        }
        return default(T);
    }
}
Ik zal eens kijken naar de NameObjectCollectionBase =)
Bedoel je nu dat je een soort van structuur wilt hebben waarbij je zowel op Index als op Key kunt zoeken ?
is het inderdaad :)

Bedankt voor de tip

[ Voor 4% gewijzigd door Verwijderd op 20-11-2006 14:52 ]


Verwijderd

Topicstarter
Nee =) er is jammer genoeg geen generics variant ..... Too bad, want het leek er wel op wat ik zocht.

HybridDictionary had beter geweest, omdat dit lijkt op een lijst die idictionary implementeert, wat ik zocht. Niet generic, dus dikke pech =p

Er moet wel een oplossing voor zijn lijkt me, want ik zal vast niet de enige zijn met dit probleem :P en een foreach loop moet gewoon netter kunnen via het framework :*)

  • whoami
  • Registratie: December 2000
  • Laatst online: 18:04
Je kan een generic wrapper bouwen rond die NameObjectCollectionBase...

https://fgheysels.github.io/


  • MTWZZ
  • Registratie: Mei 2000
  • Laatst online: 13-08-2021

MTWZZ

One life, live it!

Onthoud wel dat de volgorde van keys/values in een Dictionary niet vaststaat en zelfs compleet willekeurig kan zijn.
Kun je uitleg geven wat er precies de bedoeling is?

Nu met Land Rover Series 3 en Defender 90


Verwijderd

Topicstarter
Er worden structs in een dictionary opgeslagen met het bijbehorende ID

Dus structureel ziet het er zo uit
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[Dictionary
  [1, struct
      [id=1, name="Naam 1"]
  ],
  [2,  struct
      [id=2, name="Naam 2"]
  ],
  [3,  struct
      [id=3, name="Naam 3"]
  ],
  [53,  struct
      [id=53, name="Naam 53"]
  ],
  ...
]

Het ID van een dictionary item is het ID uit een struct.

De reden dat het generic wordt gedaan, is dat er verschillende typen structs in worden opgeslagen en op dezelfde manier afgehandeld kunnen worden. Voorheen werden de structs gewoon toegevoegd aan een List, maar was het niet mogelijk om simpel een element er uit te pikken.

Het uitlezen van zo'n dictionary aan de hand van een ID is simpel, maar aan de hand van een indexer zou het in sommige gevallen ook wel handig zijn, of in elk geval handig om te weten hoe het dan eventueel zou moeten/kunnen

Hopelijk maakt dit iets duidelijker waar het over gaat

  • MTWZZ
  • Registratie: Mei 2000
  • Laatst online: 13-08-2021

MTWZZ

One life, live it!

Ok duidelijk.
Hoewel de generic (en volgens mij de standaard) Dictionary niet heeft is een Item property dat met een integer index overweg kan. Dit komt volgens mij door de manier waarop een dictionary werkt, intern houdt dat ding een hashtable bij waardoor dat ding zo snel is bij lookups. Als je een item aan de hand van een index op wil halen (wat volgens mij niet zo handig is aangezien er geen vaste volgorde is zoals bij een stack of queue bijvoorbeeld) zul je gewoon moeten loopen zoals je al in jouw voorbeeld deed.

Je zou om het "netter" te kunnen doen gebruik kunnen maken van een IEnumerator (wat de foreach eigenlijk ook doet)
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Dictionary<string, string> dict = new Dictionary<string, string>();
dict.Add("key1", "val1");
dict.Add("key2", "val2");
dict.Add("key3", "val3");

string valueVanKey2 = dict["key2"]; // direct op key

int index = 2;   // 3e item

IEnumerator ie = dict.Keys.GetEnumerator();
while(index-- > 0) {
    ie.MoveNext();
}

string valueVanIndex = dict[ie.Current.ToString()];


Overigens zou ik als je dit gaat gebruiken een nieuwe class maken en inheriten van System.Collections.Generic.Dictionary en dan een Item property erbij klussen die een integer index accepteerd.

[ Voor 8% gewijzigd door MTWZZ op 20-11-2006 15:38 ]

Nu met Land Rover Series 3 en Defender 90


Verwijderd

Topicstarter
Juist :) we zaten ook al aan de GetEnumerator() te denken, maar dan met een for loop.

C#:
1
2
3
4
5
6
Dictionary<int,T>.Enumerator voorbeeld = objCacheDictionary.GetEnumerator();
for (int i=0;i<intpIndex;i++)
{
    voorbeeld.MoveNext();
}
objCacheDictionary[voorbeeld.Current.Key()];


Is een While loop sneller dan een for loop in C#?

  • TimTil
  • Registratie: Mei 2005
  • Laatst online: 19-10 20:19
Dit misschien

http://msdn2.microsoft.com/en-us/library/system.collections.specialized.listdictionary(VS.80).aspx


code:
1
2
3
4
        foreach (DictionaryEntry de in dict) 
        { 
            Console.WriteLine ("{0}={1}", de.Key, de.Value); 
        }

  • MTWZZ
  • Registratie: Mei 2000
  • Laatst online: 13-08-2021

MTWZZ

One life, live it!

Is een While loop sneller dan een for loop in C#?
Not so you'd notice, de gegenereerde IL is bijna hetzelfde met uitzondering van 1 stackalloc en dat ga je niet merken :D
Het is meer een kwestie van stijl.

Nu met Land Rover Series 3 en Defender 90


Verwijderd

Topicstarter
TimTil schreef op maandag 20 november 2006 @ 15:54:
Dit misschien

http://msdn2.microsoft.com/en-us/library/system.collections.specialized.listdictionary(VS.80).aspx


code:
1
2
3
4
        foreach (DictionaryEntry de in dict) 
        { 
            Console.WriteLine ("{0}={1}", de.Key, de.Value); 
        }
Niet mogelijk omdat de specialized collections niet generic zijn =) Maar bedankt in elk geval.

Het wordt de GetEnumerator() manier :D omdat het denk ik toch de mooiste oplossing is. Weinig typecasting en als er toch al generiek gewerkt wordt? =)

  • MTWZZ
  • Registratie: Mei 2000
  • Laatst online: 13-08-2021

MTWZZ

One life, live it!

Verwijderd schreef op maandag 20 november 2006 @ 15:47:
Juist :) we zaten ook al aan de GetEnumerator() te denken, maar dan met een for loop.

C#:
1
2
3
4
5
6
Dictionary<int,T>.Enumerator voorbeeld = objCacheDictionary.GetEnumerator();
for (int i=0;i<intpIndex;i++)
{
    voorbeeld.MoveNext();
}
objCacheDictionary[voorbeeld.Current.Key()];


Is een While loop sneller dan een for loop in C#?
Nog even voor de volledigheid. Als je Dictionary.GetEnumerator() doet heb je al beschikking over de value dus die hoef je niet apart op te halen. De code wordt dan:
C#:
1
2
3
4
5
6
7
Dictionary<int, T>.Enumerator dictionaryEnumerator = objCacheDictionary.GetEnumerator();

while(intpIndex-- > 0) {
    dictionaryEnumerator.MoveNext();
}

return dictionaryEnumerator.Current.Value;

Nu met Land Rover Series 3 en Defender 90


  • EfBe
  • Registratie: Januari 2000
  • Niet online
Je krijgt met een enumerator de elements er niet uit op volgorde. Ik snap niet waarom je wilt loopen, je hebt toch de key?

Verder is het opslaan van structs in datastructures zoals deze alleen voor read-only data nuttig. Het punt is dat wanneer je doet:
dict[key].Value = newValue;

je een copy wijzigt, omdat structs valuetypes zijn.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • MTWZZ
  • Registratie: Mei 2000
  • Laatst online: 13-08-2021

MTWZZ

One life, live it!

^^ als in:
Onthoud wel dat de volgorde van keys/values in een Dictionary niet vaststaat en zelfs compleet willekeurig kan zijn.

Nu met Land Rover Series 3 en Defender 90


Verwijderd

Topicstarter
EfBe schreef op woensdag 22 november 2006 @ 14:34:
Je krijgt met een enumerator de elements er niet uit op volgorde. Ik snap niet waarom je wilt loopen, je hebt toch de key?

Verder is het opslaan van structs in datastructures zoals deze alleen voor read-only data nuttig. Het punt is dat wanneer je doet:
dict[key].Value = newValue;

je een copy wijzigt, omdat structs valuetypes zijn.
Oke =) Bedankt

We gebruiken inderdaad alleen voor lezen ^_^ dus er is geen probleem.
MTWZZ schreef op woensdag 22 november 2006 @ 13:09:
[...]


Nog even voor de volledigheid. Als je Dictionary.GetEnumerator() doet heb je al beschikking over de value dus die hoef je niet apart op te halen. De code wordt dan:
C#:
1
2
3
4
5
6
7
Dictionary<int, T>.Enumerator dictionaryEnumerator = objCacheDictionary.GetEnumerator();

while(intpIndex-- > 0) {
    dictionaryEnumerator.MoveNext();
}

return dictionaryEnumerator.Current.Value;
^_^ Okee :9
Pagina: 1