PDA

View Full Version : [JAVA]Ricerca e confronto dati in una Hashtable


ermasto
27-02-2011, 14:50
Salve ragazzi, sto preparando un algoritmo di bilanciamento fatto ad agenti. Il problema è che al nodo controllore arriva una hashtable che contiene la coppia (container-carico nodo) ora io dovrei cercare all'interno della hashtable se il carico di un determinato nodo supera una determinata soglia, se la supera devo spostare l'applicazione che sto monitorado.

Il problema è che con le hashtable non sono tanto ferrato e percio vi chiedo come fare a confrontare il valore delle chiavi della hashtable con un valore esterno di soglia.

Grazie per l'aiuto.
Ciao

ermasto
09-03-2011, 21:51
:mc:

PGI-Bis
09-03-2011, 22:35
Se è una tabella Container-Carico, le chiavi sono i container e
non puoi che fare una scansione delle singole coppie contenute nella HashTable.

for(Map.Entry<Container, Carico> entry : hashtable) {
Container co = entry.getKey();
Carico ca = entry.getValue();
vedi un po' che fare con co e ca
}

Nota che qui uso due tipi, Container e Carico, non cambia nulla se uno è una stringa e l'altro un numero.

Se sai che la tabella contiene un solo container col relativo carico puoi andare a guardare direttamente il carico:

Carico c = tabella.elements().next();

Alla fine della fiera la tabella ti è utile in quanto tale, e non semplicemente in quanto collezione di coppie da macinare una per una, se conosci già la chiave, cioè il contenitore. Allora potresti dire:

Container c = il container che so essere presente nella tabella
Carico y = tabella.get(c);

Se la tabella che ti arriva contiene un numero sufficiente di dati a renderlo conveniente e le ricerce che devi fare sono più d'una, allora puoi "ottimizzare" la ricerca - dal punto di vista algoritmico - trasferendo le coppie Container-Carico (cioè i vari Map.Entry che ottieni dalla tabella con il metodo entrySet()) in un TreeSet, "ordinato" per carico. Il treeset ha dei metodi che restituiscono sottoinsiemi ottenuti per inclusione in un range di valori (subste, headset e tailset), che sono ovviamente dei log(n) anziche degli N.

ermasto
10-03-2011, 17:00
Ti ringrazio della risposta, la tabella contiene sempre piu di un container ma non è mai fissa perche ho possibità di configurarla per vari nodi cluster, quello che mi servirebbe è confrontare il carico di ogni nodo con un valore di soglia e se uno di questi carichi supera la soglia mi deve restituire il container associato al carico corrispondente.
Quindi se ho capito bene devo usare questo TreeSet per ordinare i carichi?
Hai qualche esempio per fare cio?

Grazie mille

PGI-Bis
10-03-2011, 18:24
A meno che tu non abbia una quantità esorbitante di dati ti basta la tabella e il ciclo for del post precedente.

ermasto
10-03-2011, 20:37
Sto provando con il tuo suggerimento ma ho un errore a cui non riesco a trovare soluzione

Ho tolto tutto dal for perchè mi dava un errore ma non ho capito che tipo di errore era allora per fare una prova ho fatto:


Set entries=LoadInf.entrySet();
Map.Entry entry = (Map.Entry) entries.iterator().next();
String co = (String) entry.getKey();
float ca = (float) entry.getValue();
System.out.println(co+ca);


L'errore è che nella hashtable LoadInf ho una stringa (container) e un float(carico) solo che se faccio il carico String in fase di running mi da errore perche dice che non puo fare cast tra float e string,se lo metto float in eclipse mi da errore perche dice che non puo fare cast fra object e float.
Come devo fare per eliminare quest'errore?

PGI-Bis
10-03-2011, 23:35
Usa:

float ca = (Float) entry.getValue();

nota la F maiuscola. Le mappe lavorano, sia come chiavi che come valori, su riferimenti. I tipi numerici con la lettera minuscola sono primitivi, quelli con la maiuscola denota i "wrapper" di quei primitivi. Il wrapper è, in sintesi, l'istanza di una classe che ha un campo del tipo numerico primitivo corrispondente.

L'assegnazione del valore di un Float a quello di un float funziona per via dell'auto-unboxing, in pratica dire:

float ca = (Float) entry.getValue();

equivale a dire:

Float temp = (Float) entry.getValue();
float ca = temp.floatValue();

Sarebbe meglio, per evitare errori nelle conversioni esplicite, usare i tipi parametrici, cioè avere nel codice anzichè:

Set entries=LoadInf.entrySet();

una cosa di questo genere:

Set<Entry<String, Float>> entries = LoadInf.entrySet();

quindi LoadInf sarebbe una Hashtable<String, Float>, ma, a parte il controllo sulle conversioni, non cambia nulla.

ermasto
11-03-2011, 22:45
Grazie per l'aiuto molto esauriente nelle spiegazioni, solo che vorrei un altra delucidazione su Map per applicarla al meglio nella mia applicazione.

Allora le mie coppie Container(chiave)-CaricoNodo(valore) attualmente sono 4 e restituiscono diciamo questi valori:

Main-Container@localhost 0.56
Container-1@localhost 0.50
Container-2@localhost 0.45
Container-3@localhost 0.8

Ora io ho un valore di riferimento 0.7 e in pratica, e qui chiedo il tuo aiuto, devo confrontare questi valori con quel numero e se sono piu grandi devo prelevare l'agente nel container e spostarlo nel nodo piu scarico

in quest esempio quindi nella mia ricerca devo prendere quello che c'è in container 3 e spostarlo in container 2.Lo spostamento lo so fare e funziona quello che non so fare è appunto quello di trovare e il max e il min tra questi valori.

Qui c'è una bozza dei codice ma mi ritorna sempre l'ultimo container.
float Lh=(float) 0.7;
Set entries=LoadInf.entrySet();
Iterator i=entries.iterator();
while(i.hasNext()){
Map.Entry entry = (Map.Entry)i.next();
Location co = (Location) entry.getKey();
float ca = (Float) entry.getValue();
System.out.println(co);
System.out.println(ca);
if (ca>Lh){
....
}
}

Grazie :help: :help:

PGI-Bis
12-03-2011, 00:11
Il tuo codice è corretto: lì effettivamente entry nell'if per ogni elemento che supera la soglia. Il problema potrebbe derivare dal bilanciamento durante l'iterazione, vale a dire che se cambi il carico di un elemento che hai già "ciclato" non sei più in grado di rilevare lo sforamento della soglia nel corso dello stesso ciclo: devi ripeterlo.

Se questo è il caso allora anzichè avere un ciclo sugli elementi della mappa a te interessa avere un ciclo condizionato dall'esistenza di un elemento il cui carico superi la una certa soglia. Cioè diresti:

while(condizione) {
per ogni elemento e che supera la soglia
prendi l'elemento m col carico minore
sposta un po' di carico da e a m
}

Dove condizione sarebbe:

esiste almeno un elemento con carico maggiore di un tot E
esiste almeno un elemento con carico minore di tot

Se è così (e ho un mezzo sospetto che lo sia) puoi affrontare la questione creando una tua struttura immaginaria che risponda esattamente all'esigenza che hai per poi passare a concretizzare i meccanismi attraverso cui ottieni quella risposta. Posso cioè ipotizzare che esista una struttura così definita:

package soglie;

import java.util.List;
import java.util.Map.Entry;

public interface MiaStrutturaDati {

boolean esisteContainerConCaricoMaggioreDi(float soglia);

boolean esisteContainerConCaricoMinoreDi(float soglia);

List containerConCaricoMaggioreDi(float soglia);

Entry containerConCaricoMinoreDi(float soglia);
}

Supponendo che io abbia questa struttura anzichè la hashtable, l'algoritmo di bilanciamento risulterebbe essere:

MiaStrutturaDati struttura = null;
while(struttura.esisteContainerConCaricoMaggioreDi(0.7f) && struttura.esisteContainerConCaricoMinoreDi(0.7f)) {
List daSpostare = struttura.containerConCaricoMaggioreDi(0.7f);
for (Object object : daSpostare) {
Entry containerSovraccarico = (Entry) object;
Entry containerScarico = struttura.containerConCaricoMinoreDi(0.7f);

if(containerScarico == null) { break; } //finiti i container "scarichi"

float sovraccarico = (Float) containerSovraccarico.getValue();
float scarico = (Float) containerScarico.getValue();

float bilanciamento = sovraccarico - 0.7f;

containerSovraccarico.setValue(sovraccarico - bilanciamento);
containerScarico.setValue(scarico + bilanciamento);
}
}

Il tutto funziona a patto che esista una versione concreta di MiaStrutturaDati che sia in grado di "rispondere alle domande" che gli faccio, col requisito ulteriore di lavorare partendo da una hashtable.

Una versione efficace ma non efficiente sarebbe questa:

package soglie;

import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;

public class FunnyHashtable implements MiaStrutturaDati {

private final Hashtable table;

/**
* Instance initializer
*/
public FunnyHashtable(Hashtable table) {
this.table = table;
}

public boolean esisteContainerConCaricoMaggioreDi(float soglia) {
for (Object object : table.values()) {
Float value = (Float) object;
if(value > soglia) return true;
}
return false;
}

public boolean esisteContainerConCaricoMinoreDi(float soglia) {
for (Object object : table.values()) {
Float value = (Float) object;
if(value < soglia) return true;
}
return false;
}

public List containerConCaricoMaggioreDi(float soglia) {
List entries = new LinkedList();
for (Object object : table.entrySet()) {
Entry entry = (Entry) object;
Float value = (Float) entry.getValue();
if(value > soglia) entries.add(entry);
}
return entries;
}

public Entry containerConCaricoMinoreDi(float soglia) {
for (Object object : table.entrySet()) {
Entry entry = (Entry) object;
Float value = (Float) entry.getValue();
if(value < soglia) return entry;
}
return null;
}
}

Efficace nel senso che, partendo da una hashtable, chiamiamola pippo, posso dire:

MiaStrutturaDati struttura = new FunnyHashtable(pippo);
while(struttura.esisteContainerConCaricoMaggioreDi(0.7f) && struttura.esisteContainerConCaricoMinoreDi(0.7f)) {
List daSpostare = struttura.containerConCaricoMaggioreDi(0.7f);
for (Object object : daSpostare) {
Entry containerSovraccarico = (Entry) object;
Entry containerScarico = struttura.containerConCaricoMinoreDi(0.7f);

if(containerScarico == null) { break; } //finiti i container "scarichi"

float sovraccarico = (Float) containerSovraccarico.getValue();
float scarico = (Float) containerScarico.getValue();

float bilanciamento = sovraccarico - 0.7f;

containerSovraccarico.setValue(sovraccarico - bilanciamento);
containerScarico.setValue(scarico + bilanciamento);
}
}

E ritrovarmi con la tabella bilanciata. Non è efficiente perchè se andiamo a vedere il codice è cubico, si può ridurre ad un caso medio logaritmico usando un albero ma bisogna creare dei nodi di supporto (nella fattispecie delle coppie float-List<Entry>) ma non vorrei entrare troppo nello specifico senza sapere se io abbia centrato o no il problema - e proposto una soluzione utile.

En passant, in FunnyHashtable trovi comunque il modo di ottenere gli Entry il cui valore è maggiore o minore di una certa soglia. Per ottenere non solo un Entry il cui float è minore di soglia ma anche quello che è minore tra tutti gli entry, il codice sarebbe:

public Entry containerConCaricoMinoreDi(float soglia) {
Entry risultato = null;
float minimo = soglia;
for (Object object : table.entrySet()) {
Entry entry = (Entry) object;
Float value = (Float) entry.getValue();
if(value < minimo) {
risultato = entry;
minimo = value;
}
}
return risultato;
}

ermasto
12-03-2011, 00:35
Ciao per prima cosa ti ringrazio vivamente del tuo interesse per il mio problema, stai salvando la mia tesi, ora sto cercando di leggere il tuo codice domani cerco di mettere mano modificando il mio.

Comunque in effetti la mia hashtable mi viene mandata da un altro agente che ogni tre secondi si fa un viaggetto tra i vari container e va prelevando i carichi, quando poi ha finito il giro ritorna alla base e prima di morire rilascia la hashtable a quest'agente bilanciatore che deve operare il bilanciamento.

Domattina cercherò (a mente fresca) di giocare un po col tuo codice ma, essendo pessimista, ti anticipo che dovrai rispondere a qualche domanda. :D

Grazie mille
Ciao

ermasto
12-03-2011, 16:35
Ciao allora sto provando il tuo codice e su questo ti ringrazio ancora infinitamente, sto risolvendo alcuni problemi perche l'Entry containerScarico lo devo convertire in un oggetto di tipo Location per jade ma il cast non funziona e sto trovando metodi alternativi, a meno che tu non conosci una soluzione :D, quello che ti chiedo è per il momento puramente teorico:

il mio agente ha un behaviour di tipo ciclico quindi non si ferma mai e bilancia continuamente al superamento della soglia critica, ammettiamo che ho una situazione di questo tipo:

Main-Container@localhost 0.23
Container-1@localhost 0.29
Container-2@localhost 0.75
Container-3@localhost 0.8

In questo caso la condizione di while viene verificata e nell'oggetto da spostare troviamo
Container-2 e Container-3 e i container scarichi sono Main-container e Container-1

Ora che entro nel for succede che trovo un container scarico alla volta?

Cioè nel primo ciclo for trovo come container scarico Main-container e quindi prendo quello che c'è in Container-2 e lo sposto in Main-container e al secondo for prendo quello che c'è in Container-3 e lo sposto in Container-1.

E' questo teoricamente il funzionamento del sistema di bilanciamento? Te lo chiedo per essere sicuro di aver capito bene il funzionamento.

Intanto cerco di risolvere i miei problemi cosi poi passiamo alla pratica

Ancora grazie.
Ciao Ciao

PGI-Bis
12-03-2011, 17:13
Devo premettere che le mie esperienze col bilanciamento si risolvono in una richiesta che di quando in quando faccio al gommista.

Detto questo, intendi correttamente. Il codice determina quale sia il container più scarico ad ogni passaggio nel ciclo.

Usando, attenzione, la versione del metodo containerConCaricoMinoreDi che trovi in fondo al post: quella restituisce il minimo, l'altra restitituisce semplicemente un container con carico minore della soglia.