I am storing an arrayList as my keys in a TreeMap but I am getting this exception
java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.lang.Comparable
I copy the content of array to ArrayList and try to store that arrayList as my keys in the Map
My Code is :
TreeMap< ArrayList<Integer> , Integer > bandsMap = new TreeMap< ArrayList<Integer> , Integer >();
ArrayList< Integer > erfcn = new ArrayList< Integer >();
for (int index = 0; index < frequencies.length; index++)
erfcn.add(frequencies[index]);
bandsMap.put( erfcn , band_number);
for (Integer value : bandsMap.values()) {
System.out.println("Value = " + value + "\n");
}
Any Idea ?
Thanks
A tree map maintains its keys in sorted order. The ArrayList class does not define any ordering, so it cannot be used as a key directly. You can supply an external comparator to impose an order though, but you must define an ordering that makes sense to you:
TreeMap<ArrayList<Integer>, Integer> bandsMap = new TreeMap<>(
new Comparator<ArrayList<Integer>>() {
public int compare(ArrayList<Integer> lst1, ArrayList<Integer> lst2) {
// return 1 if lst1 > lst2, 0 if equal, -1 if lst1 < lst2
}
});
Alternatively, if you don't have to maintain the keys in any particular order, use a HashMap instead.
ArrayLists don't implement Comparable, so you need to use an unsorted map, like HashMap, or tell the TreeMap how to sort your ArrayLists by using this constructor.
The error itself indicates the problem. ArrayList class does not implement java.lang.Comparable interface and the TreeMap is expecting the key to implement comparable interface. Hence it is causing the exception.
Refer ArrayList documentation.
As we cannot go modify ArrayList, you can use external comparator to make ArrayList work as a key to the TreeMap. You just need to override compare() method in it.
You can't compare two lists, you have to either change list to some other structure, or make your own list using Comparable interface. Good solution is also to wrap up list in new class which implements Comparable and implement just this method from interface.
Check out this
public class Fruit implements Comparable<Fruit>{
public int compareTo(Fruit compareFruit) {
//your code here
}
}
and this link. Hope it helps.
If you really want to use ArrayList as key in TreeMap, then you need to write Comparator for it and pass is using constructor
Using List as key in Tree is not a good idea, please review your design.
Given what the other answers have said about Lists not implementing Comparable, you could create your own class to act as TreeMap keys, extending ArrayList and implementing Comparable:
class KeyList extends ArrayList<Integer> implements Comparable<ArrayList<Integer>> {
public int compareTo(ArrayList<Integer> list) {
//decide how to compare ArrayLists, then implement it here
return 0;
}
}
Then you can create your TreeMap:
new TreeMap<KeyList, Integer>();
Related
As we all know, we need to implement Comparable interface and add compareTo() when we work with TreeSet. Not doing so will throw ClassCastException.
Now I have a TreeSet and I need to add ArrayLists as elements of TreeSet.
if we write:
ArrayList al = new ArrayList();
ArrayList al2 = new ArrayList();
ArrayList al3 = new ArrayList();
TreeSet ts = new TreeSet();
ts.add(al);
ts.add(al2);
ts.add(al3);
It throws ClassCastException.
Question: How can I add ArrayList istances (not their elements) to a TreeSet or TreeMap?
If you really need to add array list (as an instance) and not its elements, you should use another constructor rather than the empty one, consider the constructor taking as a parameter a Comparator.
TreeSet(Comparator<? super E> comparator)
Constructs a new, empty tree set, sorted according to the specified comparator.
You can define upfront a Comparator for your purpose with the meaning you actually want with regards to the concerned arraylists.
Then add the array list instances, which will properly compared according to your comparator.
As an example, you can define a Comparator which would compare array lists based on their size (sample simple comparison):
public class MyArrayListComparator implements java.util.Comparator<ArrayList> {
public int compare(ArrayList al1, ArrayList al2) {
if (al1.size() > al2.size())
return 1;
if (al1.size() < al2.size())
return -1;
return 0;
}
}
Then in your code:
ArrayList al = new ArrayList();
ArrayList al2 = new ArrayList();
ArrayList al3 = new ArrayList();
TreeSet ts = new TreeSet(new MyArrayListComparator());
ts.add(al);
ts.add(al2);
ts.add(al3);
Note the
TreeSet ts = new TreeSet(new MyArrayListComparator());
This is actually a good example of the difference between Comparable and Comparator:
Comparable is implemented by the class you want to use, with a specific behavior and you cannot change it or add it
Comparator is an external implementation you can add (if supported by the concerned consumer) with the behavior you want
Check also this SO Q/A for further details on Comparable vs Comparator.
Currently you are adding ArrayList objects and not the elements within them. As described in another answer, using the addAll will work because ultimately it will go through each ArrayList and add the individual elements.
1) As said before, you are adding ArrayList to TreeSet, not an element inside ArrayList.
al.add(__something__);
ts.add(al.get(__something-to-get-your-element-from-al__));
2) It's not recommended to use raw types, as Lists and Sets are generic types:
List<String> al = new ArrayList();
Set<String> ts = new TreeSet();
al.add("hello");
al.add("hello2");
ts.add(al.get(0));
ts.add(al.get(1));
or:
ts.addAll(al); //which will add to your TreeSet all the elements that are in the ArrayList.
EDIT: 3) probably you want to add ArrayList to TreeSet, then you have to declare the set like this:
List<String> al = new ArrayList();
//add elements to al
Set<List<String>> ts = new TreeSet();
ts.add(al);
I have an arrayList of firstName, lastName, address, email, and phoneNumber and an arrayList of multiple "entries" each with all 5 of those indexes. The methods to get and set all 5 of those values are all in the Entry class while adding, modifying, deleting, and sorting entries is done in the class Contact List.
I'm trying to sort the entries by last name and print them out in the ContactList class. I have:
public void listEntries()
{
Collections.sort(entries);
for (int i = 0; i < entries.size(); i++)
{
entries.get(i).print();
}
}
I know I'm missing something to define what to sort by, but I'm not even sure if I should be using Collections.sort. Any suggestions?
Your class with given entry (i think, that Entry is that class) must implements Comparable interface. Then you can use sort on your collection. Order is given by natural ordering (it's up to you to make your own order in implemented method of Comparable interface).
You miss a comparator as an extra argument to sort - e.g.
Collections.sort(entries, new Comparator<List<String>>() {
#Override
public int compare(List<String> o1, List<String> o2) {
return o1.get(1).compareTo(o1.get(1));
}
});
What is the most elegant way to copy keys and values from one hashtable to another between start and end keys in inverse order? For example original hashtable is:
[<1,"object1">; <2, "object2">; <4,"object3">; <5,"object4">;<7,"object5">;<8,"object6">]
after calling function getPartListOfNews(2,4) it should return hashtable like this:
[<7,"object5">;<5,"object4">;<4,"object3">]
I had made code to do it and it comes below, but I don't think is this a better way to do what i had described before. Is there ara any better solutions? How can I simplify this code?
public Hashtable<Integer, News> getPartListOfNews(int start, int end){
Hashtable <Integer, News> tempNewsList = new Hashtable <Integer, News>();
int total_to_get = end-start;
int list_size = newsList.size();
Object[] key_array = new Object[list_size];
if(list_size < total_to_get){
return newsList;
}
else{
Enumeration e = newsList.keys();
int index=0;
while(e.hasMoreElements()){
key_array[index] = e.nextElement();
index ;
}
for (int i=end; i>start; i--){
tempNewsList.put((Integer)key_array[i], newsList.get(key_array[i]));
}
return tempNewsList;
}
}
Update:
public Hashtable<Integer, News> newsList = new Hashtable<Integer, News>();
Thanks.
First, you need to use a LinkedHashMap in your newsList attribute, to preserve insertion order. Also, it's better if you declare attributes and return values of methods using the Map interface instead of the concrete class used, in this way you can easily change the implementation, like this:
private Map<Integer, News> newsList = new LinkedHashMap<Integer, News>();
With the above in mind, here's my shot at solving your problem:
public Map<Integer, News> getPartListOfNews(int start, int end) {
// first, get the range of keys from the original map
List<Integer> keys = new ArrayList<Integer>();
for (Integer key : newsList.keySet()) // iterates in insertion order
keys.add(key);
List<Integer> subkeys = keys.subList(start, end);
// now add them in the required order
Map<Integer, News> tempNewsList = new LinkedHashMap<Integer, News>();
ListIterator<Integer> iter = subkeys.listIterator();
while (iter.hasPrevious()) {
Integer key = iter.previous();
tempNewsList.put(key, newsList.get(key));
}
return tempNewsList;
}
First, your code does not have any effect. Hash table "breaks" the order. The order of elements in hash table depends on the particular hash implementation.
There are 2 types of Maps in JDK: HashMap and SortedMap (typically we use its implementation TreeMap). BTW do not use Hashtable: this is old, synchronized and almost obsolete implementation).
When you are using HashMap (and Hashtable) the order of keys is unpredictable: it depends on implementation of hashCode() method of class you are using as keys of your map. If you are using TreeMap you can use Comparator to change this logic.
If you wish your keys to be extracted in the same order you put them use LinkedHashMap.
I think a HashTable is not ordered. If you use a ordered data structure (such as LinkedHashMap) you could sort it (with java build-in methods) and make a sublist. this should be 2 lines of code and very efficiant.
I have a HashTable with alphanumeric values. I want to sort them.
How can I achieve it?
HashTable doesn't preserve the order.
So better Create a List out of it and Sort it.
You need to wrap your types into a class and then implement a Comparator that compares all the types of values (in your term),
class Foo implements Comparator<Foo>{
private int no;
private String alpha;
//+getter/setters
public int compare(Foo f1, Foo f2){
//put your logic here
}
}
Why? You presumably chose HashTable over TreeMap because it had better performance (and no ordering). If you don't want the performance and you do want the ordering, use a TreeMap.
If you don't want to create a new class to hold the key/value relationship and it you are not interested in a TreeMap, then something like the following will also work:
ArrayList<Entry<String,String>> list = new ArrayList<Entry<String,String>>();
list.addAll(map.entrySet());
Collections.sort(list, new Comparator<Entry<String,String>>() {
#Override
public int compare(Entry<String, String> o1, Entry<String, String> o2) {
//your logic here;
}
});
First question - do you really mean sort the values, or do you mean sort the keys?
If you only want to access the sorted values in order once the best way is create a list or array then sort.
For values: Arrays.sort(table.values().toArray()) or Collections.sort(new ArrayList(table.values()))
For keys: Arrays.sort(table.keySet().toArray()) or Collections.sort(new ArrayList(table.keySet()))
For more on these sorting methods: Arrays.sort() or Collections.sort().
If you want to repeatedly use based on sorted keys, you would be better using a TreeMap.
If you repeatedly want to access based on sorted values (rather than keys), then you could always insert in order into a LinkedHashMap, which will keep the ordering.
How can I create a list (or some other type of container) of integer and strings pairs that allows duplicates in both pairs and can be sorted by the integer value?
I need to fill a container with names (string) and scoring (integer) pairs, the container must allow duplicated values in both name and scoring, and i need to sort this list by the scoring value.
I tried with a SortedMap but doesn't allow duplicated values:
SortedMap<Integer,String> sm=new TreeMap<Integer, String>();
sm.put(23, "Peter");
sm.put(11, "Tony");
sm.put(110, "Claire");
sm.put(13, "ferca");
sm.put(55, "Julian");
sm.put(13, "Pedro");
In this example, ferca and Pedro have the same scoring value, this is something I need to allow, but the SortedMap overwrites "ferca" with "Pedro".
What is the best container type to do this?
Since you want your collection to be ordered, I suggest you use a List and Collections.sort. If you decide to go for this approach you still have two options:
Create a custom Comparator that can be passed as an argument to sort, or
Let the auxiliary Score class implement Comparable<Score>
Here is an example and ideone demo of the latter approach:
import java.util.*;
class Score implements Comparable<Score> {
int score;
String name;
public Score(int score, String name) {
this.score = score;
this.name = name;
}
#Override
public int compareTo(Score o) {
return score < o.score ? -1 : score > o.score ? 1 : 0;
}
}
public class Test {
public static void main(String[] args){
List<Score> scores = new ArrayList<Score>();
scores.add(new Score(23, "Peter"));
scores.add(new Score(11, "Tony"));
scores.add(new Score(110, "Claire"));
scores.add(new Score(13, "ferca"));
scores.add(new Score(55, "Julian"));
scores.add(new Score(13, "Pedro"));
Collections.sort(scores);
}
}
Create a class that enclose these two field
create a custom Comparator that compare two Objects based on int value.
Create a list of that objects
Collection.sort(); pass obj of comparator here
class MyEntity{
int val;
String name;
}
List<MyEntity> list = new ArrayList<MyEntity>();
list.add(new MyEntity(1,"a"));
list.add(new MyEntity(4,"z"));
list.add(new MyEntity(2,"x"));
Collections.sort(list,new MyComparator());
class MyComparator implements Comparator<MyEntity>{
public int compare(MyEntity ob1, MyEntity ob2){
return ob1.getVal() - ob2.getVal() ;
}
}
Note: This is just model to show the basic idea
Here is working ideone Demo
Sounds like a job for Guava's Multimap types, specifically TreeMultimap.
If you want a list, use a list...
The best option would probably be to create your own type to encapsulate the string and the integer, add your own comparison, and put them in an ArrayList<T>.
Sort it when you need to with Collections.sort.
If you don't need to allow duplicates which have the same name and score, you could use a SortedSet instead, so long as your comparison order sorts on both score and name.
After you create a holding type, an alternative structure is PriorityQueue to hold the items. This differs from Collections.sort() because the items are inserted in order, with either the high or low values rising to the top.
The only thing you have to do is write a Comparator to pass onto the PriorityQueue on instanciation, so it knows to sort the items based on the integer value.
Both this method and Collections.sort() deliver the same results with different ways of going about it. They also run in O(N log N) time.