Technology Experience

Contenuti gestiti da Igor Damiani
posts - 949, comments - 2741, trackbacks - 15120

My Links

News

  • Questo blog si propone di raccogliere riflessioni, teoriche e pratiche, su tutto quello che riguarda il world-computing che mi sta attorno: programmazione in .NET, software attuale e futuro, notizie provenienti dal web, tecnologia in generale, open-source.

    L'idea è quella di lasciare una sorta di patrimonio personale, una raccolta di idee che un giorno potrebbe farmi sorridere, al pensiero di dov'ero e cosa stavo facendo.

    10/05/2005,
    Milano

Archives

Post Categories

Generale

[70-536, #14] La classe SortedList<K, T> e l'interfaccia IComparable

Nel codice C# che ho messo a disposizione c'è un file CustomCollection.cs che contiene la definizione delle 3 classi ChapterCollection, BookCollection e ShelfCollection:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

[Serializable]
public class ChapterCollection : Collection<Chapter> { }
[Serializable]
public class BookCollection : Collection<Book> { }
[Serializable]
public class ShelfCollection : Collection<Shelf> { }

Grazie alle API create per questo tipo di applicazione, possiamo velocemente definire un nuovo Book, con i relativi Chapters nel modo seguente:

// Creo il Book
Book promessiSposi = new Book("I Promessi Sposi", "A. Manzoni", 348);
// Aggiungio tutti i Chapter di questo libro
promessiSposi.Chapters.Add(new Chapter("Prologo"));
promessiSposi.Chapters.Add(
new Chapter("Inizio della storia"));
promessiSposi.Chapters.Add(
new Chapter("Storia"));
promessiSposi.Chapters.Add(
new Chapter("Fine della storia"));
promessiSposi.Chapters.Add(
new Chapter("Epilogo"));

Fatto questo, possiamo ciclare tutti i capitoli con un banale for...each:

foreach (Chapter cycle in promessiSposi.Chapters)
    Console.WriteLine(cycle.ToString());

Quello su cui voglio porre l'attenzione oggi è che noi potremmo aggiungere i Chapter in un ordine casuale, per qualsiasi motivo. Quindi, per esempio:

promessiSposi.Chapters.Add(new Chapter("Storia"));
promessiSposi.Chapters.Add(
new Chapter("Inizio della storia"));
promessiSposi.Chapters.Add(
new Chapter("Prologo"));
promessiSposi.Chapters.Add(
new Chapter("Fine della storia"));
promessiSposi.Chapters.Add(
new Chapter("Epilogo"));

Il nostro promessiSposi contiene sempre 5 capitoli, ma sono alla rinfusa. Per ovviare a questo problema, potremmo cambiare la classe che noi abbiamo utilizzato per implementare l'elenco dei Chapter (Collection<Chapter>) ed utilizzare la nuova SortedList, disponibile solo nel FX2.0. Questa classe generica permette l'inserimento di item tramite la classica accoppiata key e value: sarà compito della classe stessa mantenere ordinata la struttura dati, utilizzando di default key come criterio per l'ordinamento stesso. Quindi, supponiamo di cambiare la dichiarazione di ChapterCollection da Collection<Chapter> e SortedList<int, Chapter>. A questo punto possiamo creare il Book ed aggiungere i capitoli uno ad uno come vogliamo noi e saremo comunque sicuri che verranno inseriti nell'ordine corretto:

Book promessiSposi = new Book("I Promessi Sposi", "A. Manzoni", 348);
promessiSposi.Chapters.Add(2, 
new Chapter("Storia"));
promessiSposi.Chapters.Add(1, 
new Chapter("Inizio della storia"));
promessiSposi.Chapters.Add(0, 
new Chapter("Prologo"));
promessiSposi.Chapters.Add(3, 
new Chapter("Fine della storia"));
promessiSposi.Chapters.Add(4, 
new Chapter("Epilogo"));

foreach (KeyValuePair<int, Chapter> cycle in promessiSposi.Chapters)
    Console.WriteLine(cycle.Value);

Il ciclo for...each mostra gli elementi ordinati, indipendentemente dall'ordine con cui li abbiamo inseriti. Questo comportamento è dovuto al fatto che il parametro K, nel nostro caso int, implementa direttamente l'interfaccia IComparable. Se così non fosse, dobbiamo occuparci noi stessi di scrivere un nostro metodo che il FX utilizzerà per ordinare gli elementi inseriti nella SortedList. Ne parlo più sotto.

Sulla pagina MSDN dedicata alla classe SortedList<K, T> ci sono alcune annotazioni per vi riporto:

  1. SortedList uses less memory than SortedDictionary
  2. SortedDictionary has faster insertion and removal operations for unsorted data, O(log n) as opposed to O(n) for SortedList
  3. If the list is populated all at once from sorted data, SortedList is faster than SortedDictionary

Scrivere un nostro Comparer
Abbiamo detto più sopra che normalmente la chiamata al metodo Add sulla nostra SortedList inserisce il nuovo elemento in base all'ordinamento con stiamo attuando in quel momento. E' importante ricordarsi che la SortedList lavora esclusivamente sulla key: quindi, se volessimo personalizzare in qualche modo il sorting dobbiamo fare in modo che l'oggetto debba essere la key. Quindi, dobbiamo ancora una volta modificare la dichiarazione della nostra SortedList in SortedList<Chapter, int>.

[Serializable]
public class ChapterCollection : SortedList<Chapter, int> { }

Adesso dobbiamo modificare la classe Chapter, facendola aderire all'interfaccia IComparable<Chapter>. Siamo quindi obbligati a scrivere un metodo come il seguente:

public int CompareTo(Chapter otherChapter)
{
    
return(_Title.CompareTo(otherChapter._Title));
}

Questo metodo viene utilizzato automaticamente al FX per il sorting, confrontando la property Title del capitolo. Partendo dal presupposto di lavorare con una Console Application, il metodo Main appare come segue:

static void Main()
{
    Book promessiSposi = 
new Book("I Promessi Sposi", "A. Manzoni", 348);
    promessiSposi.Chapters.Add(
new Chapter("Storia"), 2);
    promessiSposi.Chapters.Add(
new Chapter("Inizio della storia"), 1);
    promessiSposi.Chapters.Add(
new Chapter("Prologo"), 0);
    promessiSposi.Chapters.Add(
new Chapter("Fine della storia"), 3);
    promessiSposi.Chapters.Add(
new Chapter("Epilogo"), 4);

    
foreach (KeyValuePair<Chapter, int> cycle in promessiSposi.Chapters)
        Console.WriteLine(cycle.Key.Title);
}
// OUTPUT GENERATO
// Epilogo
// Fine della storia
// Inizio della storia
// Prologo
// Storia

In questo momento possiamo modificare il codice di CompareTo per customizzare il sorting. Ovviamente, sull'oggetto Chapter ha poco senso perchè è molto semplice e disponiamo solo della property Title. Immaginate lo stesso lavoro sulla classe Book: a seconda del codice, possiamo ordinare per titolo, pagine, autore, e così via. Senza contare che la SortedList espone una property Comparer proprio per questo scopo.

powered by IMHO 1.2

Print | posted on Friday, February 10, 2006 12:35 PM | Filed Under [ Esame 70-536 ]

Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET