Sorting a HashMap with 2 fields - java

I have a hashmap with 8 fields. Among those 2 are id and idseq. Both are integer. There can be more than one similar idseq, but not for one id. Can this hasp map be sorted on the basis of these 2?

Create a key containing these two integer values and use that as a key for your map. Make this key Comparable and implement your sorting logic there.
Something like this:
class MyCustomKey implements Comparable<MyCustomKey> {
final int id;
final int idSeq;
public MyCustomKey(int id, int idSeq) {
this.id = id;
this.idSeq = idSeq;
}
public int getId() {
return this.id;
}
public int getIdSeq() {
return this.idSeq;
}
#Override
public int compareTo(MyCustomKey o) {
// your compare logic goes here
return -1;
}
}
You can then use this as the key for your map, preferably a TreeMap if it should be sorted.

Use a TreeMap instead with custom Comparator which you should pass to its constructor.

We can use a Tree map like this:
TreeMap<Integer,DRG> sortedMap = new TreeMap<Integer,DRG>();
sortedMap.putAll(hashmap);
Treemap will take care of the rest. The order of values as represented in the database can be restored by using a Tree map.

Related

The most efficient method to find an element in Set

I have the Person class:
public class Person implements Comparable<Person> {
private int id;
#Override
public int hashCode() {
return id;
}
#Override
public boolean equals(Object obj) {
Person other = (Person) obj;
return id == other.id;
}
#Override
public int compareTo(Person o) {
return Integer.compare(id, o.id);
}
}
And I have TreeSet of persons.
I need to implement method findPersonById(int id) in TreeSet.
I made it this way:
public Person find(int id) {
List<Person> personList = new ArrayList(idTreeSet);
Person pattern = new Person(id);
int index = Collections.binarySearch(personList, pattern);
return index < 0 ? null : personList.get(index);
}
Now the efficient of the find method is O(n) because it needs to copy all of elements from TreeSet to ArrayList.
But is there more efficient way to implement this method?
I don't need a Map. I'm interesed to resolve it without Maps.
Since you are prepared to allocate a temporary Person object, you can do it like this:
public Person find(int id) {
Person temp = new Person(id);
Person candidate = idTreeSet.ceiling(temp);
return temp.equals(candidate) ? candidate : null;
}
This is O(logN).
Note that we only create one temporary object here. If we use tailSet or subSet we will be creating at least second one; i.e. the NavigableSet returned by the tailSet or subSet call. (Looking under the hood of the TreeSet implementation, it looks like more will be created.)
If you don't need the properties of a TreeSet then using a HashMap<Integer, Person> or a HashSet<Person> would give you O(1) lookup. But in the latter case, you need change your Person class to satisfy the equals / hashCode contract.
Because TreeSet is a NavigableSet, you can use TreeSet.subSet, which leverages knowledge about the order of the elements to extract a range of elements as close as possible to the element you are interested in:
Person pattern = new Person(id);
return
// Get the Persons between pattern (inclusive) and pattern (inclusive).
// In other words: all the Persons with id equal to the input,
// of which there are zero or one.
idTreeSet.subSet(pattern, true, pattern, true).stream()
.findFirst()
.orElse(null);
Map<Integer, Person> personsById = new HashMap<>();
Would definitely be fastest, though not Tree based. A LinkedHashMap for order of insert would allow some order.
It is the more rugged solution.

Java Hash Tables and Hash Maps

Have been going through the Java for sometime now and got stuck at yet another question. HashMaps or HashTables.
have gone through the basics..how a hash table is implemented..like calculating a hash value..storing data at the hash value(or probably hashvalue % maxArray) index..linear probing and chaining for collisions.
Now to further, if somebody could please help with below:
Basic examples show storing Strings like "Jhon", "Lisa" , "Sam" etc in an array then going through collisions and converting the array to Linked list to store the names which is all good to understand and super fine.
But Hashtables store Key,Value pair. So how it is achieved?
The key,value pair examples show "Telephone Directory" example, but they do not show how they are stored in Arrays or linked list. It is just Map.put(k,v) and Map.get(k). Linked list store "One Data" and "Pointer".. so how can we store both Keys and Values in Linked list( A picture might help in understanding)
A bit more practical example for Hash Table than map.put("Rocket", 01111111111).
But Hashtables store Key,Value pair. So how it is achieved?
Imagine a data structure like this:
Node<K, V>[] table;
public static class Node<K, V> {
//voila! Key and Value stored here
private K key;
private V value;
//make it a linked list
private Node<K, V> next;
}
The key,value pair examples show "Telephone Directory" example, but they do not show how they are stored in Arrays or linked list. It is just Map.put(k,v) and Map.get(k). Linked list store "One Data" and "Pointer".. so how can we store both Keys and Values in Linked list( A picture might help in understanding)
Check point 1.
A bit more practical example for Hash Table than map.put("Rocket", 01111111111).
Here you go:
public class PersonIdentifier {
private final int id;
private final String ssn;
public PersonIdentifier(int id, String ssn) {
this.id = id;
this.ssn = ssn;
}
//getters, NO setters since fields are final...
//now the relevant methods!
#Override
public int hashCode() {
//available since Java 7...
return Objects.hash(id, ssn);
}
#Override
public boolean equals(Object o) {
if (o == null) return null;
if (this == o) return true;
if (!o.getClass().equals(this.getClass())) return false;
Person another = (Person)o;
return another.id == this.id && another.ssn.equals(this.ssn);
}
}
//...
Map<PersonIdentifier, Person> peopleMap = new HashMap<>();
peopleMap.put(new PersonIdentifier(1, "123456789"), new Person(/* fill with values like firstName, lastName, etc... */));
peopleMap.put(new PersonIdentifier(2, "987654321"), new Person(/* fill with values like firstName, lastName, etc... */));
//and on...

Sorting List of lists/ Arraylists/ Hashmaps with multiple values in Java

I want to create a table like structure in Java as shown in the image
Table structure
Though I am not an expert in Java, I have tried to implement it using Arraylist structure as follows:
List<List<Double>> dataList = new ArrayList<List<Double>>();
for(int x = 0; x < n; x++){
List<Double> tempList = new ArrayList<Double>();
dataList.add(tempList);
}
for(int y = 0; y < n; y++){
double execution = exectime[y];
double cost= cost[y];
dataList.get(y).add(execution);
dataList.get(y).add(cost);
}
for (int z=0;z<dataList.size();z++) {
Double v1=dataList.get(z).get(0);
Double v2=dataList.get(z).get(1);
System.out.println("ID"+z +" Execution time:" + v1 + "cost: " + v2);
}
Where the values of 'n', 'exectime[n]' and 'cost[n]' will be read from a file and 'n' is the total number of 'ids' that needs to be created.
After creating the table, I want to sort it based on the 'execution time' value and 'cost' value, both increasing and decreasing order. Please help me in this regards.
#snovelli's answer about using a class to encapsulate your data is a good point.
If you are using Java 8, you can easily create and chain comparators that use accessors.
For sorting a list of objects, it might look something like:
List<ExecutionTimeData> dataList = new ArrayList<>();
dataList.sort(Comparator
.comparing(ExecutionTimeData::getExecutionTime)
.thenComparing(ExecutionTimeData::getCost));
Sorting by execution time, followed by cost.
You could also use this to sort a List<List<Double>> if you really wanted to.
List<List<Double>> doubleListList = new ArrayList<>();
doubleListList.sort(Comparator
.comparing((List<Double> l) -> l.get(0))
.thenComparing(l -> l.get(1)));
Sorting by element 0 of the list, followed by element 1.
Or for sorting in reverse order:
List<ExecutionTimeData> dataList = new ArrayList<>();
dataList.sort(Comparator
.comparing(ExecutionTimeData::getExecutionTime).reversed()
.thenComparing(ExecutionTimeData::getCost).reversed());
Use Collections.sort() with Comparator.
However, you will loss your ID information because it is based on your index of the ArrayList. Therefore, if you use this method and want to keep you ID information, you need to add() ID to your ArrayList just like execution and cost.
Comparator<List<Double>> ORDER = new Comparator<List<Double>>() {
#Override
public int compare(List<Double> lhs, List<Double> rhs) {
if (lhs.get(1) < rhs.get(1)) return -1;
if (lhs.get(1) == rhs.get(1)) return 0;
return 1;
}
};
Collections.sort(dataList, ORDER);
In above code, your dataList will sorted with cost, because it is at the index 1 of the ArrayList.
However, the better way (in readability) is you put your column into a Class, not just a ArrayList. For example, you can create a Class like this:
class Information {
private int id;
private double execution;
private double cost;
Information(int id, double execution, double cost) {
this.id = id;
this.execution = execution;
this.cost = cost;
}
}
And implement static Comparator inside that class. It will improve the readability of your code.
I think You should use a Chained Comparator to implement sorting using multiple attributes. Because If you use a single Comparator Individually It will sort the data according to its own Compare() Method Implementation.
Better to Go with Chained Comparator which sort your data on multiple attribute ... Try the Following Link ==> Sorting a list by multiple attributes example
Use Collections as List < RegisterType > , RegisterType is created according to the type of registers present in the table (ex: with 3 double atributes)
Implement the Comparator interface Comparator< RegisterType >
Override the compare( RegisterType o1, RegisterType o2) method the way you want (define how to sort 2 elements of type RegisterType)
Inkove Collections.sort(List< RegisterType > list, ComparatorClass)
Then you will have your collection list sorted the way you want.
A table is a way to represent a list of objects, why not use a list of object then?
I think you want to have a SortedSet of a class that you could define as:
public class ExecutionTimeData{
private final long id;
private final long executionTime;
private final int cost;
public ExecutionTimeData(long id, long executionTime, int cost){
this.id = id;
this.executionTime = executionTime;
this.cost = cost;
}
/* Getters */
}
Then you will simply have an unsorted list like
List<ExecutionTimeData> unsortedList = new ArrayList<>();
As pointed out from #VikrantKashyap to order the list with both value and cost you then must implement a Chained Comparator
public class ExecutionTimeDataChainedComparator implements Comparator<ExecutionTimeData> {
private List<Comparator<ExecutionTimeData>> listComparators;
#SafeVarargs
public ExecutionTimeDataChainedComparator (Comparator<ExecutionTimeData>... comparators) {
this.listComparators = Arrays.asList(comparators);
}
#Override
public int compare(ExecutionTimeData etd1, ExecutionTimeData etd2) {
for (Comparator<ExecutionTimeData> comparator : listComparators) {
int result = comparator.compare(etd1, etd2);
if (result != 0) {
return result;
}
}
return 0;
}
}
And implement the comparators like this
public class ExecutionTimeDataCostComparator implements Comparator<ExecutionTimeData > {
#Override
public int compare(ExecutionTimeData a, ExecutionTimeData b) {
return b.getCost() > a.getCost()?-1:1;
}
}
public class ExecutionTimeDataExecutionComparator implements Comparator<ExecutionTimeData > {
#Override
public int compare(ExecutionTimeData a, ExecutionTimeData b) {
return b.getExecutionTime() > a.getExecutionTime()?-1:1;
}
}
And of course you can find out an easy way to invert the order by instantiating the comparators providing ASCENDING or DESCENDING order

Sort on first entry of ArrayList in ArrayList

I have an ArrayList that consists of an ArrayList that constists of Strings: ArrayList<ArrayList<String>>. How can I sort on the first entry of he inner ArrayList? For example I would like this:
a = [['1','apple'],['3','pear'],['2','banana'],['1',orange']]
to become:
a_sorted = [['1','apple'],['1','orange'],['2','banana'],['3','pear']]
The order of duplicate first entries (like apple and orange) do not matter. I've tried using Collections.sort(a,new ColumnComparator()) but it will not accept ArrayLists. This is the class I used:
public class ColumnComparator implements Comparator<ArrayList<String>>{
public int compare(ArrayList<String> ar1, ArrayList<String> ar2){
return ar1.get(0).compareTo(ar2.get(0));
}
}
Instead of storing an Array of an Array, why don't you create a custom Class that implements Comparable. eg.
class Fruit implements Comparable<Fruit> {
protected int number;
protected String name;
public Fruits(int number, String name) {
this.number = number;
this.name = name;
}
#Override
public int compareTo(Fruit f) {
return number < f.number;
// or depending on if ascending or descending order wanted
// return number > f.number
}
}
Then to sort just run Collections.sort(a). This way is flexible and easily extended.
You can create a Map <String, ArrayList<String>> with first entry of the ArrayLists as key and the ArrayList itself as value. Then sort the Map (use Sorted Map or a Comparator to sort on the Map keys) on keys and you will get what you want.
Why cant you use a this ArrayList<Map<String,String>> instead of ArrayList<ArrayList<String>>. You can easily sort the Map on the key by using TreeMap.
Note: This will only work if you have only two entries in your inner arraylist.
If you really want to do it that way, you can try this:
import java.util.Comparator;
public class ColumnComparable implements Comparator<ArrayList<String>>{
#Override
public int compare(ArrayList<String> o1, ArrayList<String> o2) {
return (Integer.parseInt(o1.get(0)) > Integer.parseInt(o2.get(0)) ? -1 : (Integer.parseInt(o1.get(0)) == Integer.parseInt(o2.get(0)) ? 0 : 1));
}
}
The code was found here.

how to swap key in map?

is there a way to sort this numbers stored in a string variable?
TreeMap<String,List<QBFElement>> qbfElementMap = new TreeMap<String, List<QBFElement>>();
this is the map where the key is :
27525-1813,
27525-3989,
27525-4083,
27525-4670,
27525-4911,
27526-558,
27526-1303,
27526-3641,
27526-4102,
27527-683,
27527-2411,
27527-4342
this is the list of keys and the value for each of the key is a list.
now, how can i sort this key in ascending order by number.
ex. if i want to sort : 1,2,11,20,31,3,10
i want to have as output is : 1,2,3,10,11,20,31
but when i use the autosort of treemap the output goes : 1,10,11,2,20,3,31
how can i sort it in ascending order by numeric?
and the language is java :) thank you:)
The keys in your map are not Integer but String values. That's why the key's are sorted like observed.
Either change the Map to
TreeMap<Long,List<QBFElement>> qbfElementMap
or create it with a specialized Comparatorthat will provide the expected numerical order for the String type keys.
A mapping from your String values to Longs could be done like this:
private Long convertToLongTypeKey(String key) {
String[] parts = key.split("-");
// next lines assumes, that the second part is in range 0...9999
return Long.parseLong(parts[0]) * 10000 + Long.parseLong(parts[1]);
}
An implementation of Comparator<String> could use the same mapping to create a numerical comparision of two String based keys:
new TreeMap<String,List<QBFElement>>(new Comparator<String>(){
#Override
public int compare(String key1, String key2) {
String[] parts1 = key1.split("-");
Long long1 = Long.parseLong(parts1[0]) * 10000 + Long.parseLong(parts1[1]);
String[] parts2 = key2.split("-");
Long long2 = Long.parseLong(parts2[0]) * 10000 + Long.parseLong(parts2[1]);
return long1.compareTo(long2);
}
});
You can change the way that the TreeMap sorts its keys by providing a custom comparator to the constructor. If you want, you can define a new Comparator that compares strings by breaking them up into numeric components.
It seems like a better idea, though, would be to not use Strings as your keys. The data you're using as keys is clearly not textual - it's numeric - and you might want to define a custom type to represent it. For example:
public class KeyType implements Comparable<KeyType> {
private final int first;
private final int second;
public KeyType(int first, int second) {
this.first = first;
this.second = second;
}
#Override
public boolean equals(Object other) {
if (!(other instanceof KeyType)) return false;
KeyType realOther = (KeyType) other;
return realOther.first == first && realOther.second == second;
}
#Override
public int hashCode() {
return first + 31 * second;
}
public int compareTo(KeyType other) {
if (first != other.first)
return first - other.first;
return second - other.second;
}
}
This approach is the most expressive and robust. It gives you better access to the individual fields of the keys you're using, and also prevents you from adding nonsensical keys into the map like the string "Lalalalala". I'd strongly suggest using this approach, or at least one like it. The type system is your friend.
A TreeMap can take a custom comparator for custom sorting. Write a comparator that sorts the keys the way you want and use it when you create the treemap
TreeMap<String,List<QBFElement>> qbfElementMap = new TreeMap<String, List<QBFElement>>(myComparator);

Categories

Resources