2009-04-08 18 views
5

Se si dovesse avere un sistema di denominazione nella vostra applicazione in cui l'applicazione contiene dire 100 azioni, che crea nuovi oggetti, come:Generare la prossima disponibile nome univoco in C#

Blur 
Sharpen 
Contrast 
Darken 
Matte 
... 

e ogni volta che si utilizza uno Di questi, una nuova istanza viene creata con un nome modificabile univoco, come Blur01, Blur02, Blur03, Sharpen01, Matte01, ecc. Come si genera il prossimo nome univoco disponibile, in modo che si tratti di un'operazione O (1) o quasi costante . Tenete a mente che l'utente può anche cambiare il nome ai nomi personalizzati, come RemoveFaceDetails, ecc

E 'accettabile avere alcuni vincoli, come limitare il numero di caratteri a 100, utilizzando lettere, numeri, caratteri di sottolineatura, ecc ..

MODIFICA: È inoltre possibile suggerire soluzioni senza "riempire gli spazi vuoti" che è senza riutilizzare i nomi già utilizzati, ma cancellati, ad eccezione di quelli personalizzati, naturalmente.

+0

Solo per essere difficile: se si utilizza lo schema suggerito, come si prevede di distinguere il 113 "Sfocatura" (Blur112) e il 13 "Blur1" (anche Blur112)? –

+0

Buon punto, non ci ho pensato. Immagino di doverlo pensare. Qualche idea? –

risposta

7

Vorrei creare un numero intero statico in action class che viene incrementato e assegnato come parte di ogni nuova istanza della classe. Per esempio:

class Blur 
{ 
    private static int count = 0; 

    private string _name; 
    public string Name 
    { 
     get { return _name; } 
     set { _name = value; } 
    } 

    public Blur() 
    { 
     _name = "Blur" + count++.ToString(); 
    } 
} 

Dal conteggio è statica, ogni volta che si crea una nuova classe, verrà incrementato e aggiunto al nome predefinito. O (1) tempo.

EDIT

Se è necessario riempire i buchi quando si elimina, vorrei suggerire quanto segue. Sarebbe coda automaticamente i numeri quando gli elementi vengono rinominati, ma sarebbe più costoso complessiva:

class Blur 
    { 
     private static int count = 0; 
     private static Queue<int> deletions = new Queue<int>(); 

     private string _name; 
     public string Name 
     { 
      get { return _name; } 
      set 
      { 
       _name = value; 
       Delete(); 
      } 
     } 

     private int assigned; 

     public Blur() 
     { 
      if (deletions.Count > 0) 
      { 
       assigned = deletions.Dequeue(); 
      } 
      else 
      { 
       assigned = count++; 
      } 
      _name = "Blur" + assigned.ToString(); 
     } 

     public void Delete() 
     { 
      if (assigned >= 0) 
      { 
       deletions.Enqueue(assigned); 
       assigned = -1; 
      } 
     } 
    } 

Inoltre, quando si elimina un oggetto, avrete bisogno di chiamare .Delete() sull'oggetto.

versione CounterClass dizionario

class CounterClass 
{ 
    private int count; 
    private Queue<int> deletions; 

    public CounterClass() 
    { 
     count = 0; 
     deletions = new Queue<int>(); 
    } 

    public string GetNumber() 
    { 
     if (deletions.Count > 0) 
     { 
      return deletions.Dequeue().ToString(); 
     } 
     return count++.ToString(); 
    } 

    public void Delete(int num) 
    { 
     deletions.Enqueue(num); 
    } 
} 

è possibile creare un dizionario per cercare i contatori per ogni stringa. Assicurati di analizzare l'indice e chiama .Delete (int) ogni volta che rinomina o cancelli un valore.

+0

Questo è quello che sono venuto qui per dire. – GWLlosa

+0

Grazie Mark, ma per quanto riguarda l'eliminazione degli oggetti? –

+0

Hai ancora dei nomi univoci dopo la cancellazione, solo con un 'buco' nella sequenza. È davvero un problema? – GWLlosa

3

potete facilmente possibile farlo in O(m) dove m è il numero di istanze esistenti del nome (e non dipende n, il numero di elementi nella lista.

  1. Cercare la stringa S in questione . Se S non è nella lista, il gioco è fatto.
  2. S esiste, in modo da costruire S+"01" e verificare la presenza di questo. Continuare incrementando (ad es prossimo provare S+"02" fino a quando esso non esiste.

Questo ti dà nomi univoci ma sono ancora "belli" e leggibili.

A meno che non si preveda un numero elevato di duplicati, questo dovrebbe essere "quasi costante" perché m sarà così piccolo.

Avvertimento: se la stringa naturalmente termina con es "01"? Nel tuo caso questo sembra improbabile, quindi forse non te ne importa. Se ti interessa, considera l'aggiunta di più di un suffisso, ad es. "_01" invece di "01", quindi è più facile distinguerli.

+0

Buona idea per il trattino basso. –

0

Se si desidera il tempo O (1), è sufficiente tenere traccia del numero di istanze di ciascuna di esse. Mantieni una tabella hash con tutti gli oggetti possibili, quando crei un oggetto, incrementa il valore per quell'oggetto e usa il risultato nel nome.

+0

Questo non è abbastanza. L'utente può rinominare un oggetto esistente con un nome che verrà generato in seguito con conseguente collisione. –

0

Non vorrai assolutamente esporre un GUID all'interfaccia utente.

Stai proponendo un nome iniziale come "Blur04", che consente all'utente di rinominarlo e quindi genera un messaggio di errore se il nome personalizzato dell'utente è in conflitto? O rinominandolo in silenzio a "CustomName01" o altro?

È possibile utilizzare un dizionario per verificare la presenza di duplicati nell'ora O (1). È possibile avere contatori incrementali per ogni tipo di effetto nella classe che crea le nuove istanze di effetti. Come ha detto Kevin, diventa più complesso se devi riempire gli spazi nella numerazione quando un effetto viene cancellato.

+0

Sì, il nome iniziale dice che sarà Box04, e poi se lo rinominano in qualcos'altro devono farlo esplicitamente. Non sarà modificabile subito perché la maggior parte delle volte non cambieranno il nome delle cose. Quando lo fanno, è anche unico o l'app aggiungerà il prossimo numero disponibile. –

7

vi rimando al di Michael A. Jackson Two Rules of Program Optimization:

  1. Non pratico.
  2. Solo per esperti: non farlo ancora.

semplice, il codice mantenibile è molto più importante di ottimizzazione per un problema di velocità che si pensi potrebbe hanno seguito.

Vorrei iniziare in modo semplice: creare un nome candidato (ad esempio "Sharpen01"), quindi scorrere i filtri esistenti per vedere se quel nome esiste. Se lo fa, incrementalo e riprova. Questo è O (N), ma finché non ottieni migliaia di filtri, sarà sufficiente.

Se, qualche volta dopo, l'O (N) diventa un problema, quindi inizierei creando un hash di nomi esistenti. Quindi puoi controllare il nome di ogni candidato contro l'HashSet, piuttosto che iterare. Ricreare HashSet ogni volta che è necessario un nome univoco, quindi buttarlo via; non hai bisogno della complessità di mantenerlo di fronte ai cambiamenti. Questo lascerebbe il tuo codice facile da mantenere, pur essendo solo O (N).

O (N) sarà sufficiente. Non hai bisogno di O (1). L'utente non farà clic su "Precisione" abbastanza volte perché ci possa essere qualche differenza.

2

Si potrebbe fare qualcosa di simile:

private Dictionary<string, int> instanceCounts = new Dictionary<string, int>(); 

    private string GetNextName(string baseName) 
    { 
     int count = 1; 

     if (instanceCounts.TryGetValue(baseName, out count)) 
     { 
      // the thing already exists, so add one to it 
      count++; 
     } 

     // update the dictionary with the new value 
     instanceCounts[baseName] = count; 

     // format the number as desired 
     return baseName + count.ToString("00"); 
    } 

Si potrebbe quindi semplicemente utilizzarlo chiamando GetNextName (...) con il nome di base che si voleva, come ad esempio string myNextName = GetNextName("Blur");

Usando questo, non dovresti pre-avviare il dizionario. Si riempirebbe come hai usato le varie parole di base. Inoltre, questo è O (1).

+0

Grazie Erich, come gestisci la cancellazione di oggetti, detti "buchi"? –

+0

Esiste un buon motivo per gestire questo caso nella pratica? Se si desidera gestire i fori, è possibile utilizzare un elenco ordinato per contenere i nomi eliminati. Dizionario > holes = new ... per eliminare, aggiungere l'elemento eliminato ai fori [nome_base] e controllare tale elenco prima del dizionario di conteggio. –

+0

In realtà questo è un buon suggerimento, non penso che ci sia una ragione convincente. Sono tutto per le migliori pratiche, quindi se non aggiunge alcun valore, posso lasciarlo fuori. –

1

Vorrei creare un dizionario con una chiave stringa e un valore intero, memorizzando il numero successivo da utilizzare per una determinata azione. Questo sarà quasi O (1) nella pratica.

private IDictionary<String, Int32> NextFreeActionNumbers = null;  

private void InitializeNextFreeActionNumbers() 
{ 
    this.NextFreeActionNumbers = new Dictionary<String, Int32>(); 

    this.NextFreeActionNumbers.Add("Blur", 1); 
    this.NextFreeActionNumbers.Add("Sharpen", 1); 
    this.NextFreeActionNumbers.Add("Contrast", 1); 
    // ... and so on ... 
} 

private String GetNextActionName(String action) 
{ 
    Int32 number = this.NextFreeActionNumbers[action]; 

    this.NextFreeActionNumbers[action] = number + 1; 

    return String.Format("{0} {1}", action, number); 
} 

E sarà necessario verificare le collisioni con i valori modificati dall'utente. Ancora una volta un dizionario potrebbe essere una scelta intelligente. Non c'è modo di aggirare questo. In qualunque modo generi i tuoi nomi, l'utente può sempre modificare un nome esistente con quello successivo che generi, a meno che non includi tutti i nomi esistenti nello schema di generazione. (Oppure usa un carattere speciale che non è consentito nei nomi modificati dall'utente, ma non sarebbe bello.)

A causa dei commenti sul riutilizzo dei fori, voglio aggiungerlo anche qui. Non riutilizzare i fori generati da rinominare o eliminare. Questo confonderà l'utente perché i nomi che ha cancellato o modificato riappariranno all'improvviso.

1

Vorrei cercare modi per semplificare il problema.

Ci sono dei vincoli che possono essere applicati? Ad esempio, sarebbe buono se ogni utente potesse avere solo un tipo (attivo) di azione? Quindi, le azioni potrebbero essere distinte utilizzando il nome (o ID) dell'utente.

  • Blur (Ben F)
  • Blur (Adrian H)
  • Focus (Ben F)

Forse questo non è un'opzione in questo caso, ma forse qualcosa d'altro sarebbe possibile . Farei di tutto per evitare la complessità di alcune delle soluzioni proposte!

+0

Ciao Lars, ma ci saranno più di 1 della stessa azione. E nel grande schema delle cose, tutte queste azioni saranno visibili e sì uno o più saranno selezionati, ecc. –

+0

Puoi usare la data è stata creata invece del nome, o forse una piccola descrizione che specifica cosa fa uno Sfocatura diversa dall'altra? Perché ci sono molti per cominciare? –

Problemi correlati