Raggruppamento di oggetti in base a una serie di campi

5

Vorrei ordinare un elenco di persone in bucket, come duplicati, tramite un confronto email, ma non riesco a trovare un modo efficiente.

Specifiche

  • Una persona ha 5 campi email, quindi per sapere se una persona è un duplicato di quest'ultima, devo confrontare ciascuna delle sue e-mail con ognuna delle ultime.

  • A potrebbe essere duplicato di B e C, ma l'unico modo di sapere è confrontare A con B e poi B con C (vedi l'immagine qui sotto) .

  • Il mio input è un elenco di record di, ad esempio, 5.000 tra i quali potrebbero non esserci duplicati, tutti potrebbero essere la stessa persona o qualsiasi altra combinazione casuale di duplicità.

Quindi, tutto sommato, come posso inserire questo elenco di persone in bucket? Inizialmente pensavo di farlo annidando un ciclo e confrontando ogni record con ogni altro record e, se lo erano corrispondenza, creare una lista che salverei in un altro elenco, in quel modo raggruppandoli. Il problema è che ho quindi dovuto nidificare ancora un altro ciclo per iterare gli elenchi creati al fine di convalidare che un record non era un duplicato di nessuno dei precedenti. I parametri di riferimento di questo, ovviamente, erano orribili.

    
posta Javier García Manzano 16.03.2018 - 17:52
fonte

2 risposte

6

Questo problema è noto, AFAIK, come "partizionamento di un set in classi di equivalenza", ma non sono riuscito a trovare ad hoc una buona risorsa web per questo, quindi provo a dare un profilo generale di un algoritmo efficiente:

La parte esterna è semplice:

Inizia con un set vuoto di benne. Ogni bucket contiene un elenco di persone e, per ogni coppia di bucket diversi, gli indirizzi email comuni delle persone associate di ciascun bucket saranno disgiunti in qualsiasi momento.

  1. itera su tutte le persone P

  2. Per ogni indirizzo email di P: determina se esiste già un bucket correlato - > ti fornisce una lista B di bucket (che potrebbero essere vuoti)

  3. se B è vuoto (nessuno degli indirizzi email di P corrisponde a nessuno dei bucket precedenti), crea un nuovo bucket che contiene solo questa persona

  4. se B contiene esattamente un elemento, metti P in quel bucket (ed estendi di conseguenza l'elenco di indirizzi email del bucket)

  5. se B contiene 2 o più bucket, unisci questi bucket in uno (ed estendi di conseguenza l'elenco di indirizzi email di questo nuovo bucket)

Quindi non resta che scegliere alcune efficienti strutture dati che supportano le operazioni richieste:

  • ogni bucket deve contenere un gruppo di persone - > un elenco di persone per ciascun bucket lo farà

  • efficiente aggiunta di persone a un bucket e fusione di bucket - > un elenco è ancora valido

  • efficiente ricerca di bucket via email: significa che hai bisogno di un dizionario aggiuntivo D che mappa email -> bucket .

Quest'ultimo può essere aggiornato in modo efficiente quando viene aggiunto un nuovo bucket, quando un bucket riceve altri indirizzi e-mail o quando verranno uniti due bucket (il che significa che gli indirizzi e-mail nel dizionario dovranno essere rimappati nella fusione appena creata benna).

Per recuperare definitivamente tutti i bucket trovati, puoi fare un po 'di contabilità durante il processo sui bucket appena creati e quelli che sono stati cancellati durante l'unione (alcuni hashset aggiuntivi per tutti i bucket validi faranno il trucco), o tu può scorrere tutti i valori di quel dizionario e rimuovere i bucket duplicati (vedere alcune soluzioni Java standard qui ).

Lo schizzo sopra può essere reso ancora più efficiente utilizzando la cosiddetta "struttura dei dati disgiunti" invece di un elenco di persone per ciascun bucket, ma per la mia esperienza per molte applicazioni pratiche è sufficiente un elenco.

    
risposta data 16.03.2018 - 21:05
fonte
3

Un (altro) modo per affrontare questo problema è riconoscerlo come equivalente alla ricerca di componenti connessi in un grafico.

Un modo per costruire un grafico (bipartito) rilevante è considerare come nodi "persone" (ad esempio Persona 1, Persona 2, ...) e come un altro insieme di nodi tutti gli indirizzi di posta elettronica (unici). Un margine tra i nodi esiste quando una "persona" ha un dato indirizzo email. Una volta disegnato il grafico, il problema del bucketing / merging equivale a trovare i componenti collegati del grafico, cosa che può essere fatta ad esempio utilizzando la ricerca in profondità.

Per un problema molto simile, vedi ad es. link per alcune soluzioni Python (le tuple ci sono i tuoi elenchi di messaggi di posta elettronica).

    
risposta data 17.03.2018 - 17:25
fonte

Leggi altre domande sui tag