Conjunto de conjuntos (Set)

Caros,
Como trabalhar com conjuntos de conjuntos em java. (conjuntos de conjuntos de conjuntos,etc).

Ex:

Set<Set<Integer>> ss = new TreeSet<Set<Integer>>();	
		Set<Integer> s1 = new TreeSet<Integer>();
		Set<Integer> s2 = new TreeSet<Integer>();
		
		s1.add(1);
		s1.add(2);
		s1.add(2);
		
		s2.add(1);
		s2.add(2);
		
		
		System.out.println(s1);
		System.out.println(s2);
		
		ss.add(s1);
		ss.add(s1);
		
		System.out.println(ss);

java.lang.ClassCastException: java.util.TreeSet cannot be cast to java.lang.Comparable at java.util.TreeMap.put(TreeMap.java:559) at java.util.TreeSet.add(TreeSet.java:255)

Como tenho, por exemplo, TreeSet de TreeSet. Como definir o comparable?

Obrigado

não entendi a ideia de ter isso??
podes fazer assim

Map<Integer,Set<Integer>>> aux = new TreeMap<Integer,Set<Integer>>();

Em teoria de conjuntos um conjunto pode ser composto por conjuntos. Quero abstrair essa ideia em uma classe q encapsular alguma classe q implementa a interface Set

Você está usando a implementação TreeSet, que mantém os elementos ordenados, e por isso precisa que os elementos sejam Comparable.
Substitua por HashSet que não terá essa restrição. Como você está simulando o modelo matemático de conjuntos isso não será problema pois na matemática os conjuntos não são ordenados.

olha q viagem…

public class Teste {
	public static void main(String[] args) {
		Map<List<Integer>, List<Integer>> aux = new HashMap<List<Integer>, List<Integer>>();

		List<Integer> conjunto1 = new ArrayList<Integer>(0);
		List<Integer> subConjunto = new ArrayList<Integer>(0);
		conjunto1.addAll(Arrays.asList(1,5,3,8,9,2));
		subConjunto.addAll(Arrays.asList(9,6,8,7,0,1));
		aux.put(conjunto1, subConjunto);
	}
}

eu preciso das propriedades de conjunto e preciso percorrer indexado (precisa ter ordem).

Observei q a LinkedHashSet implementa a interface set e mantem ordenado. Contudo, nao consigo fazer um getElementAt(index). Tem alguma classe q implementa Set mantem ordenado e possui um getElementAt?

Set que mantém ordenado (pensando na iteração através dos elementos) tem essas que vc citou, TreeMap que ordena de acordo com a ordenação natural (interface Comparable) e a LinkedHashSet que permanece a ordem em que foram inseridos.

Já acessar por índice é outra história. Por natureza essa característica é incompatível com um conjunto (Set)
Fale mais sobre sua necessidade, pode ser que exista outra estrutura de dados mais apropriada para o problema. Talvez uma List possa oferecer as operações que você precisa, ou em último caso talvez até mesmo uma implementação própria (IndexableSet ? ).

basicamente, preciso de todas as operações de conjunto basicas (adicionamente preciso q esteja ordenado pela ordem de inserção e percorrer indexado).

Interface:

	public boolean removeElement(K element); 
	public void add(K element) throws SetException;  
	public boolean contains(K element);  
	public boolean pertence(K element); 
	public K getElmentAt(int index); 
	public boolean eguals (IntSet<K> set); 
	public boolean empty();  
	public boolean subSet(IntSet<K> set); 
	public boolean subSet(K set);  
	public boolean subSetProper(IntSet<K> set); 
	public IntSet<K> diference(IntSet<K> set) throws SetException ; 
	public IntSet<K> diference(K element) throws SetException ;  
	public int getCardinality(); 
	public int size(); 
	public Iterator<K> getIterator(); 
	public Object clone() throws CloneNotSupportedException; 
	public IntSet<K> union(IntSet<K> set) throws SetException;  
	public IntSet<K> union(K element) throws SetException; 
	public IntSet<K> intersection(IntSet<K> set) throws SetException;

Para variar precisar ser eficiente. O problema do getElementAt é que existe muito codigo pronto q utiliza. Mudar tudo para iterator e usar a LinkedHashSet q mantem a ordem será muito complicado.

[quote=smd]Interface:

	public boolean removeElement(K element); 
	public void add(K element) throws SetException;  
	public boolean contains(K element);  
	public boolean pertence(K element); 
	public K getElmentAt(int index); 
	public boolean eguals (IntSet<K> set); 
	public boolean empty();  
	public boolean subSet(IntSet<K> set); 
	public boolean subSet(K set);  
	public boolean subSetProper(IntSet<K> set); 
	public IntSet<K> diference(IntSet<K> set) throws SetException ; 
	public IntSet<K> diference(K element) throws SetException ;  
	public int getCardinality(); 
	public int size(); 
	public Iterator<K> getIterator(); 
	public Object clone() throws CloneNotSupportedException; 
	public IntSet<K> union(IntSet<K> set) throws SetException;  
	public IntSet<K> union(K element) throws SetException; 
	public IntSet<K> intersection(IntSet<K> set) throws SetException;

[/quote]
Partindo dessa interface, eu criaria uma implementação baseada em um LinkedHashSet, porque ele tem duas características fundamentais para o problema: oferece as operações de conjunto (contém, não contém, união, intersecção, etc) de forma eficiente e armazena os elementos em ordem de inserção.

Essa implementação seria basicamente um decorator, que adapta as operações nativas do Set para a interface desejada.

// Só um rascunho, nao ligue para os erros de compilacao.
class IntSet<K> {
     private LinkedHashSet<K> innerset;

     public boolean removeElement(K element) {
            innerset.remove(element);
     }


     public boolean contains(K elem) {
            return innerset.contains(elem);
     }

     public boolean contains(IntSet<K> set) {
            return innerset.containsAll(set);
     }

     public boolean subSet(IntSet<K> set) {
            return set.containsAll(innerset);
     }

     public IntSet<K> union(IntSet<K> set) throws SetException {
            LinkedHashSet u = new LinkedHashSet(innerset);  // Copia o conjunto atual
            u.addAll(set); // Adiciona o segundo conjunto
            return new IntSet<K>(u);    // Retorna um novo conjunto com a união.
     }

     // assim por diante, implementando todas as operações
}

O problema ficaria por conta do getElementAt(index). Uma implementação possível seria fazer esse método iterar pelos elementos até chegar ao desejado. Essa iteração seria transparente para a classe que está usando o conjunto.

// Também só um rascunho, nao sei se compila e nao tem tratamento de range invalido. K getElmentAt(int index) { int i = 0; Iterator iter = innerset.iterator(); while (i < index) { i++; iter.next(); } return iter.next(); } Como dá para ver, esse processo não é muito otimizado, mas é o preço a pagar para ter eficiência nas operações de busca. Dependendo do caso não é nada de outro mundo, a própria LinkedList faz algo parecido quando vc pede um elemento pelo index. Vale a pena testar e ver se atende às necessidades.

[color=blue]Obs 1:
Tem algumas dessas operações que acho que não fazem sentido, dê uma conferida… subSet, diference e union não se aplicam a elementos, apenas a outro conjunto.[/color]

[color=red]Obs 2:
Gostaria de ver outras opiniões a respeito, se dá para melhorar tudo isso. Vou ficar de olho no tópico!
[/color]

Minha ideia de solução é essa mesmo. Mas penso em manter um list adicional

	protected LinkedHashSet<K> set;
	protected ArrayList<K> list;

para ter a ordem.

Outra solução que pensei é em implementar a classe do zero utilizando bitset.

Ideias!?!

[quote=smd]penso em manter um list adicional

	protected LinkedHashSet<K> set;
	protected ArrayList<K> list;

para ter a ordem.[/quote]
Essa solução é eficiente se a aplicação faz mais buscas por índice do que alterações nos conjuntos.

Como a lista precisa ser atualizada a cada alteração no set, o benefício da performance pode acabar se perdendo quando as alterações forem muito frequentes.
Mas se as buscas predominam então esse custo para manter a lista vai ser um bom negócio.

Caros,

Ainda na saga de conjuntos em java.

Observei que a classe LinkedHashSet utiliza a soma do hash dos objetos para criar seu proprio hash.

Suponha que o numero do conjunto seja o próprio hash.
Set A={1,2,3,4} =hash =10
Set B ={2,3,5} = hash =10

Nesse caso retorna se true para A==B, o que obviamente é um absurdo. Como identificar unicamente um conjunto? Não me venham com a proposta de ordená-los!

Todas as soluções para conjuntos em java parecem me ruins. A melhor das idéias me parece usar bitSet, mas deparo-me com problemas como: bitsets de tamanho distintos, ordem dos elementos para comparar dois conjuntos.

Idéias, sugestões, opiniões!!!

Isso é perfeitamente normal!

Se os objetos A e B tem hash igual a 10 e os objetos são diferentes não há nada de errado nisso, o hash não é um identificador único.

Veja essas discussões:


Mas se quiser pode tentar melhorar um pouco o hash do seu conjunto. Sobrescreva o hashCode para fazer algo como:

hashTotal = hash(elemento1) + hash(elemento2)*2 + hash(elemento3)*3 + hash(elemento4)*4 + ....

Vai reduzir as colisões em alguns casos, por exemplo conjuntos com os mesmos elementos em ordens diferentes, mas as coincidências vão continuar a existir, então talvez seja um trabalho desnecessário.

O problema é que o hash (soma dos elementos) é utilizado pela LinkedHashSet para identificar o conjunto, o que vai gerar o erro mostrado na mensagem anterior. O exemplo anterior é um bug (pode gerar um). Para o hashe ser utilizado é necessário identificar unicamente o conjunto.