Login Login
MORE

WIDGETS

Widgets

Wanted articles
Who is online?
Article tools

CSharp:Dictionary

From Aino Wiki

Jump to: navigation, search

Ottimi esempi: Dot Net perls

Es. 1

Supponendo di creare una cache di documenti HTML in memoria il cui valore è oggetto del HTML Agility Pack:

using System.Collections.Generic;
...
private static Dictionary<string, HtmlAgilityPack.HtmlDocument> DictEmailTemplate = new Dictionary<string, HtmlAgilityPack.HtmlDocument>();
...
HtmlAgilityPack.HtmlDocument docHTML = new HtmlAgilityPack.HtmlDocument();
 
// Verifica se il Template è stato caricato prima
if (!DictEmailTemplate.ContainsKey(fullPathFileNameTemplate))
{
	// Caricamenteo File
	HtmlAgilityPack.HtmlDocument docHTMLNew = new HtmlAgilityPack.HtmlDocument();
	docHTMLNew.Load(fullPathFileNameTemplate);
	DictEmailTemplate.Add(fullPathFileNameTemplate, docHTMLNew);
}
else
{
	docHTML = DictEmailTemplate[fullPathFileNameTemplate];
}

Ciclo sulle coppie

Brutalmente copiato da DotNet perl, in attesa di mia sistemazine.

using System;
using System.Collections.Generic;
 
class Program
{
    static void Main()
    {
	// Example Dictionary again
	Dictionary<string, int> d = new Dictionary<string, int>()
	{
	    {"cat", 2},
	    {"dog", 1},
	    {"llama", 0},
	    {"iguana", -1}
	};
	// Loop over pairs with foreach
	foreach (KeyValuePair<string, int> pair in d)
	{
	    Console.WriteLine("{0}, {1}",
		pair.Key,
		pair.Value);
	}
	// Use var keyword to enumerate dictionary
	foreach (var pair in d)
	{
	    Console.WriteLine("{0}, {1}",
		pair.Key,
		pair.Value);
	}
    }
}

Output

cat, 2
dog, 1
llama, 0
iguana, -1

cat, 2
dog, 1
llama, 0
iguana, -1

Rimozione

Rimozione per valore

Metodo con scansione lineare:
foreach (KeyValuePair<string, UA_AISInfo> ai in m_DctUA_AIS)
{
	if (ai.Value.NodeDisplayName == id)
	{
		m_DctUA_AIS.Remove(ai.Key);
		break;
	}
}
Il seguente è testato:
private static void RemoveByValue<TKey,TValue>(Dictionary<TKey, TValue> dictionary, TValue someValue)

{

   List<TKey> itemsToRemove = new List<TKey>();
   foreach (var pair in dictionary)
   {
       if (pair.Value.Equals(someValue))
           itemsToRemove.Add(pair.Key);
   }

 

   foreach (TKey item in itemsToRemove)
   {
       dictionary.Remove(item);
   }
}
Richiamato così:
Dictionary<int, string> dictionary = new Dictionary<int, string>();
dictionary.Add(1, "foo");
dictionary.Add(2, "foo");
dictionary.Add(3, "bar");
string someValue = "foo";
RemoveByValue(dictionary, someValue);

Es.1

Stesso risultato col metodo diretto (non funziona):
var item = m_DctUA_AIS.First(x => x.Value.NodeDisplayName == id);
m_DctUA_AIS.Remove(item.Key);

Rimozione multipla

Esempio preso da StackOverflow:
foreach ( var s in MyCollection.Where(kv => kv.Value.Member == foo).ToList() ) {
  MyCollection.Remove(s.Key);
}

Pare elimini il problema della eliminazione durante l'enumerazione della lista stessa. Il ToList() alla fine FORZA l'enumerazione prima che il ForEach inizi le azioni previste.

Ordinamento

Da dotNetPerls, usando LinQ:
using System;
using System.Collections.Generic;
using System.Linq;
 
class Program
{
    static void Main()
    {
	var items = new Dictionary<int, int>();
	items.Add(-1, 0);
	items.Add(0, 1);
	items.Add(-2, 0);
	items.Add(3, 1);
 
	// Use OrderBy method.
	foreach (var item in items.OrderBy(i => i.Key))
	{
	    Console.WriteLine(item);
	}
    }
}

Posizionamento

Accedere ad un elemento

Per avere chiave e valore di un elemento mediante indice numerico, usando Linq:

Dictionary<string,string> dizionario = new Dictionary<string,string>();
//.. riempio il dizionario
var primo = dizionario.First(); // coppia ordinata del dizionario in posizione uno
string key = primo.Key;
Dictionary<string,string> val = first.Value;

Accedere all'elemento in posizione n

La premessa è che la richiesta è mal posta in quanto un dizionario non implementa l'accesso posizionale e sarebbe stato meglio usare una lista. Tuttavia riporto esempio da stackoverflow.

cipher = new Dictionary<char,int>;
cipher.Add( 'a', 324 );
cipher.Add( 'b', 553 );
cipher.Add( 'c', 915 );
// ....
int n = 0; // Elemento desiderato
int nthValue = cipher[cipher.Keys.ToList()[n]];

Soluzioni varie

Aggiunta o aggiornamento

SOLUZIONE FONDAMENTALE!
dato un dizionario esiste un modo COMPATTO per aggiungere un elemento se non esiste e per aggiornarlo nel caso esista già. Questo eviterà errori di aggiunta per elementi che si da per scontato che non esistano. E' un metodo potente ma altrettanto pericoloso quindi va usato con consapevolezza.

foreach (KeyValuePair<string, NodeSubscribedInfo> dctItmNS in dctNodeSubscrInfo)
{
	// modo compatto per aggiungere un elemento se non esiste altrimenti lo si aggiunge
	m_DctMainNodeSubscribed[dctItmNS.Key] = dctItmNS.Value; // <----------- !!!!!!!!!!!!
}

Aggiunta di un dizionario ad un altro

Da stackoverflow:
foreach(var newAnimal in NewAnimals)
    Animals.Add(newAnimal.Key,newAnimal.Value);
Ma per evitare i duplicati e rendere la cosa generica per un eventuale helper:
public static void AddRange<T>(this ICollection<T> target, IEnumerable<T> source)

{

   if(target==null)
     throw new ArgumentNullException("target");
   if(source==null)
     throw new ArgumentNullException("source");
   foreach(var element in source)
       target.Add(element);
}

Selezioni

Selezionare un sottoDizionario da uno di partenza

private Dictionary<string, ItemDictionaryInfo> m_ItemsDictionarySubscription = new Dictionary<string, ItemDictionaryInfo>();
 
//...
 
foreach (KeyValuePair<string, ItemDictionaryInfo> pItemSubscription in m_ItemsDictionarySubscription
                                               .Where(x => !string.IsNullOrEmpty(x.Value.SubscriptionItemsNamePattern)))
{
   // qualcosa da fare...
}

Selezionare un sottoinsieme di coppie del dizionario

Da stackoverflow, usando ToDictionary():
Dictionary<string, Object> Data;
Dictionary<string, int> IntData = Data.Where(k => k.Value is int)
   .ToDictionary(kv => kv.Key, kv => (int) kv.Value);

Caricamento Dizionario con un XML

Il metodo è fatto per caricare due tipi di XML diversi, ovvero con diverso numero di attributi per elemento:Primo XML:
<?xml version="1.0" encoding="utf-8" ?>
<OpcServerConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <key key="#Wind"
       subPath="Wind,Meteorology/Wind"
       attributes="Speed,Angle" />
 
  <key key="#AirTemperature"
       subPath="AirTemperature,Meteorology/Temperature/Air"
       attributes="Temperature" />
 
  <key key="#AirPressure"
         subPath="AirPressure,Meteorology/Barometer"
         attributes="Pressure" />
 
  <key key="#AirHumidity"
           subPath="AirHumidity,Meteorology/Humidity"
           attributes="Relative" />
  <key key="#AIS" 
       subPath="AIVDM,NavigationalData/AIS/Class_A|AIVDO,NavigationalData/AIS/Own_Ship" 
       attributes="AttitudeData.Bearing,AttitudeData.Course,AttitudeData.Distance,AttitudeData.Heading,AttitudeData.Speed,Callsign,Destination,Draught,ETA,TypeOfShip,ShipsDimension.rpoint_a,ShipsDimension.rpoint_b,ShipsDimension.rpoint_c,ShipsDimension.rpoint_d,IMONR,MMSI,Position.Latitude,Position.Longitude,Position_Accuracy,ROT_Valid,RateOfTurn,ShipsName,Status,TypeOfShip"/>
</OpcServerConfig>
Secondo XML:
<?xml version="1.0" encoding="utf-8" ?>

<OpcServerConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

 <key key="#Wind"

type="FixedItems" attributes="Speed,Angle" />

 <key key="#Waypoints"

type="Event" itemsNamePattern="D" attributes="Identifier,Position.Latitude,Position.Longitude" />

</OpcServerConfig>
Segue metodo di caricamento:
        public static Dictionary<string, ItemDictionaryInfo> LoadItemsDictionary(string path)
       {
           Dictionary<string, ItemDictionaryInfo> itemsDictionary = new Dictionary<string, ItemDictionaryInfo>();

 

           XDocument xmlItemMapping = XDocument.Load(path);

 

           string key = string.Empty;
           string subPath = string.Empty;
           string attributes = string.Empty;
           ItemDictionaryInfo itemMapping = new ItemDictionaryInfo();

 

           foreach (XElement element in xmlItemMapping.Descendants("key"))
           {
               key = element.Attribute("key").Value;
               itemMapping = new ItemDictionaryInfo();

 

               #region Acquisizione VALORI del dizionario
               #region Info esclusive DIZIONARIO PRINCIPALE
               if (element.Attribute("subPath") != null)
               { 
                   subPath = element.Attribute("subPath").Value;
               }
               else
               {
                   subPath = string.Empty;
               }
               if (!string.IsNullOrEmpty(subPath))
               { 
                   string[] arrSubPath = subPath.Split('|');
                   itemMapping.SubPaths = new Dictionary<string, string>();
                   foreach (string s in arrSubPath)
                   { 
                       string[] arrItemsSubPath = s.Split(',');
                       itemMapping.SubPaths.Add(arrItemsSubPath[0], arrItemsSubPath[1]);
                   }
               }
               if (element.Attribute("itemsNamePattern") != null)
               {
                   itemMapping.SubscriptionItemsNamePattern = element.Attribute("itemsNamePattern").Value;
               }
               #endregion

 

               #region Info esclusive SUBSCRIPTION
               if (element.Attribute("type") != null)
               {
                   itemMapping.SubscriptionType = EnumsAcquisitor.ParseEnum<EnumsAcquisitor.EnumSubscriptionType>(element.Attribute("type").Value);
               }
               else
               {
                   itemMapping.SubscriptionType = EnumsAcquisitor.EnumSubscriptionType.FixedItems;
               }
               #endregion

 

               // Attributi COMUNI
               attributes = element.Attribute("attributes").Value;
               itemMapping.AttributesCSV = attributes;
               #endregion

 

               itemsDictionary.Add(key, itemMapping);
           }
           return itemsDictionary;
}
Fa riferimento ad un oggetto del seguente tipo\classe:
    public class ItemDictionaryInfo
    {
        #region Properties
        /// <summary>
        ///  In riferimento all'esempio di sopra, potrà contenere le info associate alla chiave: 
        ///     #AIS
        /// </summary>
        public Dictionary<string, string> SubPaths
        {
            get;
            set;
        }
 
        /// <summary>
        /// Indica se la sottoscrizione è di tipo "FixedItems" o "Event". La prima è quella più 
        /// semplice costituita da un elenco di nodi con relativi attributi da acquisire con subscription
        /// mentre la seconda riguarda informazioni che pur essendo sotto un percorso fisso posso variare 
        /// cioè essere aggiunti o sottratti ciascun elemento però ha un insieme fisso di attributi da acquisire.
        /// </summary>
        public EnumsAcquisitor.EnumSubscriptionType SubscriptionType
        {
            get;
            set;
        }
 
        /// <summary>
        /// Per identificare l'appartenenza di un elemento ad una entità o meno lo si fa (cosa introdotta DOPO)
        /// in base alla radice del nome dell'item sottoscritto e che ha subito un cambio stato (nuove info).
        /// Es. è un AIS se Inizia con 'M', è un ARPA (target) se inizia per 'Target', è un Waypoint se inizia per 'D', etc
        /// </summary>
        public string SubscriptionItemsNamePattern
        {
            get;
            set;
        }
 
        /// <summary>
        ///  In riferimento all'esempio di sopra, potrà contenere:
        ///     Destination,Draught,IMONR,MMSI,Position.Latitude,Position.Longitude,RateOfTurn,ShipsName,Status
        /// </summary>
        public string AttributesCSV
        {
            get;
            set;
        }
        #endregion
}

Conversione da Dictionary a List

Per convertire dun dizionario in una lista delle sue chiavi

listNumber = dicNumber.Select(kvp => kvp.Key).ToList();

oppure

listNumber = dicNumber.Keys.ToList();

Ricerca

Sostanzialmente si usa il metodo ContainsKey, poi per avere la posizione assoluta si trasforma il dizionario in LISTA...
(probabilmente per queste operazioni sarebbe stato meglio altra struttura rispetto al dizionario ma per picoli insiemi di dat magari è comodo).

public static void Main()
{
    string fileName = string.Empty;
    string fileNameFullPath = string.Empty;
 
    m_DictCurrItemDocFileLst.Add("fileName1", "path\\fileName1");
    m_DictCurrItemDocFileLst.Add("fileName2", "path\\fileName2");
    m_DictCurrItemDocFileLst.Add("fileName3", "path\\fileName3");
    m_DictCurrItemDocFileLst.Add("fileName4", "path\\fileName4");
    m_DictCurrItemDocFileLst.Add("fileName5", "path\\fileName5");
 
    fileName = "fileName5";		
 
    if (m_DictCurrItemDocFileLst.ContainsKey(fileName))
    {
        m_IndxCurrItemDocFileLst = m_DictCurrItemDocFileLst.Keys.ToList().IndexOf(fileName);
    }
    else
    {
        m_IndxCurrItemDocFileLst+= -1;
    }		
    Console.WriteLine("File '{0}', in posizione '{1}'!", fileName, m_IndxCurrItemDocFileLst);
}

Mappa e Link


C#


Hashtable Parole chiave:ToDictionary , LinQ

Author