how to swap key in map? - java

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);

Related

Add number in map java

I am creating a function that loops through a string, separates it by comma and then takes the key from the second item in the array and the value from the 1st after splitting the string.
I then want to place these values in a map. This works perfectly, however if i have two strings with the same key it doesn't add the value up it just replaces it.
For example if my string was
123,totti 100,roma, 100,totti
I would want
totti 223
roma 100
Here is my code
private void processCallLogs(String[] splitCalls) {
for (String individualCall : splitCalls) {
int duration = 0;
String[] singleCall = individualCall.split(",");
duration += DurationParser.returnDuration(singleCall[0]);
this.cost += CalculateCost.calculateCostPerCall(singleDuration);
if (totalCallDurations.containsKey(singleCall[1])) {
totalCallDurations.put(singleCall[1], singleDuration);
} else {
totalCallDurations.put(singleCall[1], duration);
}
}
}
You can replace the if with something like this:
if (totalCallDurations.containsKey(singleCall[1])) {
duration += totalCallDurations.get(singleCall[1]);
}
totalCallDurations.put(singleCall[1], duration);
Create a map and update the value if the key is present
public static void main(String[] args) {
myMap = new HashMap<>();
// 123,totti 100,roma, 100,totti
addToMap("totti", 123);
addToMap("roma", 100);
addToMap("totti", 100);
System.out.println(myMap);
}
private static void addToMap(String string, int i) {
int t = i;
if (myMap.get(string) != null) {
t += myMap.get(string);
}
myMap.put(string, t);
}
If you're using Java 8, you can do this easily with the Map.merge() method:
totalCallDurations.merge(singleCall[1], duration, Integer::sum);
If you want to make a map that will add the values together instead of replacing, I would recommend extending the Map type to make your own map. Since Map is very abstract. I would extend HashMap. (I suggest this both for code style and because it will make your code more extendable).
public class AdderMap extends HashMap<String, Integer> { // This extends the HashMap class
public Integer get(String key) { // This overrides the Map::get method
if(super.containsKey(key)) return super.get(key); // If the key-value pairing exists, return the value
else return 0; // If it doesn't exist, return 0
}
public Integer put(String key, Integer value) { // This overrides the Map::put method
Integer old_value = this.get(key); // Get the former value of the key-value pairing (which is 0 if it doesn't exist)
super.put(key, old_value + value); // Add the new value to the former value and replace the key-value pairing (this behaves normally when the former value didn't exist)
return old_value; // As per the documentation, Map::put will return the old value of the key-value pairing
}
}
Now, when you initialize your map, make it an AdderMap. Then, you can just use put(String, Integer) and it will add it together.
The advantage of this solution is that it helps with keeping your code clean and it allows you to use this type of map again in the future without needing separate code in your main code. The disadvantage is that it requires another class, and having too many classes can become cluttered.

How to sort an array of objects w.r.t. key using Java?

My question might seem ditto duplicate, but I have seen several questions and could not satisfy my quest.
I have a data like this:
index value
1 220
2 123
3 11123
4 440
5 3400
I have saved it into String[] data= new String[5]; as following:
data[0]= 1 + " " + 220;
data[1]= 2 + " " + 123;
...
Now what I do is:
Arrays.sort(data);
What it does is sorting, but w.r.t. 1st column.
I want this to do it for me w.r.t. 2nd column.
Is it possible or if I am wrong?
Also I am not sure if this is the right way I have used to save this kind of data?
How about, if I want to use int(s) to save these values, how will everything go?
i.e. from saving data to get it sorted in formal Java style?
EDIT: This is a two columns case, where I have said index and value. I am particularly interested in a case with more than two columns and different data types. Where sorting should be performed w.r.t. the elements of any column specified.
Create a class to hold your two related data elements (index and value) as fields (presumably with getters and setters). Write two Comparator classes, one that sorts by index and one that sorts by value. I would probably create factory methods in the class to get these Comparators.
Rather than create an array of String, you would create an array of your new class. Construct your class instances and assign to the array.
Than you can use Arrays.sort on your array with whichever Comparator is appropriate to efficiently sort the array. This also allows you easy access to the individual fields.
Bro - here is some code to get you started...
public class Bro {
private int index;
private int value;
public Bro (int index, int value) {
this.index = index;
this.value = value;
}
public static Comparator<Bro> getIndexComparator() {
return new Comparator<Bro>() {
public int compare(Bro o1, Bro o2) {
return o1.index - o2.index;
}
}
}
}
Bro[] bros = new Bro[5];
bros[0] = new Bro(1, 220);
...
Arrays.sort(bros, Bro.getIndexComparator());
Java provides two similar interfaces: Comparator and Comparable. If a class has a natural sort order, you would implement Comparable. If you need to sort a class in more than one way, you will implement a Comparator for each sort order that you need.
I would suggest to use a Tuple class to hold your key/values and then use a comparator to
sort based on keys/values. Something like the following. It's written using Java 8.
class Main {
public static void main(String[] args) {
Tuple[] data = new Tuple[5];
data[0] = new Tuple(1, 220);
data[1] = new Tuple(2, 123);
data[2] = new Tuple(3, 11123);
data[3] = new Tuple(4, 440);
data[4] = new Tuple(5, 3400);
Arrays.sort(data, (t1, t2) -> t1.value - t2.value);
}
}
class Tuple {
int key;
int value;
public Tuple(int key, int value) {
this.key = key;
this.value = value;
}
#Override
public String toString() {
return "(" + key + ", " + value + ")";
}
}
About the general case, I'm afraid in Java you cannot define a type with unknown number of generic types. But if you know beforehand how many columns yo have, you can do the following:
class Tuple<T1 extends Comparable<T1>, T2 extends Comparable<T2>, ..., Tn extends Comparable<Tn>> {
T1 col_1;
T2 col_2;
...
Tn col_n;
public Tuple(T1 col_1, T1 col_2, ..., Tn col_n) {
this.col_1 = col_1;
this.col_2 = col_2;
...
this.col_n = col_n;
}
#Override
public String toString() {
return "(" + col_1 + ", " + ... + col_n + ")";
}
}
And then sort based on the column number as follows:
Arrays.sort(data, (t1, t2) -> t.col_i.compareTo(t2.col_i))
So essentially, each column type knows how to compare itself with its own type.
You can use a custom comparator to re-split the strings only during the comparisons, and compare using the int values. So instead of using
Arrays.sort(data);
You should use:
Arrays.sort(data, new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
int val1 = Integer.valueOf(o1.split(" ")[1]);
int val2 = Integer.valueOf(o2.split(" ")[1]);
// Ascending
if (val1 > val2) {
return 1;
} else if (val1 == val2) {
return 0;
}
return -1;
}
});
You might want to consider using a Map for this kind of data. With index as key and value as the data associated with the key.
Or the the other way round if you want to sort using value mostly.
Something like:
TreeMap<Integer, Integer> dataMap = new TreeMap<>(); //sorts the entries according to key
dataMap.add(220, 1);
dataMap.add(123, 2);
...
You can further lookup bunch of methods to iterate over TreeMap here.

First N values of a Map<K, V> sorted by value

I have a list of Strings. I want to evaluate each string based on a function that returns a double. Then I want the first 5 strings, based on their calculated values. If there are fewer than 5, I want all of them (in order). Let's say the strings are chemical compounds and the function computes the mass. The function is computationally expensive; I need to evaluate it once per string. (I'm just making up data here, though.)
H2O => 18.5
C12H11O22 => 109.1
HeNe => 32.0
H2SO4 => 54.37
HCl => 19.11
4FeO3 => 82.39
Xe6 => 281.9
The program should return the first five strings arranged in order by their respective values. For this sample data: H20, HCl, HeNe, H2SO4, 4FeO3. Actually, I don't really care about the order; I just need the five lowest in any order.
I thought about how I'd do this in Perl. It's just a few lines:
foreach $s (#str) {
$strmap{$s} = f($s);
}
#sorted = sort { $strmap{$a} <=> $strmap{$b} } keys %strmap;
return #sorted[0, 4]
But I need to do it in Java. And it's driving me crazy.
First I tried populating a HashMap<String, Double>, then using Collections.sort with a custom comparator, just like the Perl version. But scoping on the Comparator prevented it from referring to the HashMap to look up the values.
Then I tried a TreeMap<String, Double>, but it only sorts by key and no amount of coercing could get it to order the entries by value.
So I tried a TreeMap<Double, String>. It will discard entries with the same Double. However, the likelihood of having Strings that map to the same Double is low, so I pressed forward. Adding the entries to the TreeMap is no problem, but I ran into issues trying to extract the values from it.
TreeMap supplies a method called subMap, but its parameters are the keys that delimit the subset. I don't know what they are; I just want the first five of them. So I tried using the values method to get all the values out of the TreeMap, hoping they'd be in order. Then I can just get the first ten.
ArrayList<String> strs = (ArrayList<String>)(treemap.values());
return new ArrayList<String>(strs.subList(0, 5));
Nope. Runtime error: cannot cast TreeMap$Values to ArrayList.
List<String> strs = (List<String>)(treemap.values());
return new ArrayList<String>(strs.subList(0, 5));
Same. Runtime error trying to do the cast. OK, let's just assign to a Collection...
Collection<String> strs = treemap.values();
return new ArrayList<String>(strs.subList(0, 5));
Sorry, subList isn't a method of Collection.
Collection<String> strs = treemap.values();
ArrayList<String> a = new ArrayList<String>(strs);
return new ArrayList<String>(a.subList(0, 5));
Finally, something that works! But two extra data structures just to get the first five elements? And I'm not too wild about using Double as the key for TreeMap.
Is there a better solution?
I don't think you'll get more compact than the three lines above, not in Java.
Apart from that, I have the impression that a Map as a data structure is the wrong choice in the first place, since you do not seem to need by-string lookups (UNLESS you want in some way deal with multiple occurences of strings, but you didn't say so). An alternative approach would be to declare your own comparable data record class:
private static class Record implements Comparable<Record> {
// public final fields ok for this small example
public final String string;
public final double value;
public Record(String string, double value) {
this.string = string;
this.value = value;
}
#Override
public int compareTo(Record other) {
// define sorting according to double fields
return Double.compare(value, other.value);
}
}
// provide size to avoid reallocations
List<Record> records = new ArrayList<Record>(stringList.size());
for(String s : stringList)
records.add(new Record(s, calculateFitness(s));
Collections.sort(records); // sort according to compareTo method
int max = Math.min(10, records.size()); // maximum index
List<String> result = new ArrayList<String>(max);
for(int i = 0; i < max; i++)
result.add(records.get(i).string);
return result;
This is now much more verbose than the three lines above (this is Java, after all), but also includes the code that would be required to insert the key/value pairs into the map.
Would something like the following work for you?
Note that I've assumed you don't require the double value other than to sort the data.
public static void main(String[] args) throws Exception {
List<String> data = new ArrayList<>(Arrays.asList("t", "h", "i", "s", "i", "s", "t", "e", "s", "t", "d", "a", "t", "a"));
Collections.sort(data, new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
double o1Value = evaluate(o1);
double o2Value = evaluate(o2);
return Double.compare(o1Value, o2Value);
}
});
List<String> result = data.subList(0, 10); // Note the end point is exclusive
for (String s : result) {
System.out.println(s);
}
}
private static double evaluate(String s) {
return s.codePointAt(0); // Nonsense, I know
}
This example prints:
a
a
d
e
h
i
i
s
s
s
Why don't you just create a class to combine the String, Double and function that does the calculation - something like:
public Thing implements Comparable<Thing>
{
private String s;
private Double d;
public Thing(String s)
{
this.s = s;
this.d = calculateDouble(s);
}
public String getString()
{
return this.s;
}
public Double getDouble()
{
return this.d;
}
public int compareTo(Thing other)
{
return getDouble().compareTo(other.getDouble());
}
public Double calculateDouble(String s)
{
...
}
}
Then all you need is a List<Thing>, Collections.sort and List.subList.

how can Ikeep one and remove other duplicate arrayList objects and update another object property?

I need your help in JAVA (with some sample code if possible) regarding to the following scenario:
I have a list with a classes object and want to check if one object property has duplicates then keep one of them and add others amounts with the kept one's amount. For example:
I have this class:
class Salary {
String names;
Double amount;
}
and the list say salary_list contains the following elements in it(for example):
[jony,john 300.96]
[fuse,norvi,newby 1000.55]
[john,jony 22.6]
[richard,ravi,navin 55.6]
[fuse,norvi,newby 200.6]
... ... ...
So what is my expected output is the same input list with the following revised result:
[jony,john 323.56]
[fuse,norvi,newby 1201.15]
[richard,ravi,navin 55.6]
N.B: order in names is not important so not the order of the elements after the duplicate elimination.
I am not good at english as well as in Java. So forgive me if any mistakes there.
Thanks in advance.
Enhance your Salary class as follows:
class Salary {
String names;
Double amount;
private String sortedNames = null;
#Override
public boolean equals(Object o)
{
if (o == null || ! (o instanceof Salary)) return false;
Salary othr = (Salary) o;
String thisNames = this.getSortedNames();
String othrNames = othr.getSortedNames();
return thisNames.equals(othrNames);
}
#Override
public int hashCode()
{
return getSortedNames().hashCode();
}
public String getSortedNames()
{
if (this.sortedNames == null)
{
String[] nameArr = this.names.split(",");
Arrays.sort(nameArr);
StringBuilder buf = new StringBuilder();
for (String n : nameArr)
buf.append(",").append(n);
this.sortedNames = buf.substring(buf.length()==0?0:1);
}
return this.sortedNames;
}
}
This assumes that Salary is immutable (that is, after it's created the values of names and amount won't change. You could then use this with a hash map to add up all the amounts having the same names.
Map<String,Salary> map = new HashMap<String,Salary>();
for (Salary s : list)
{
Salary e = map.get(s.getSortedNames());
if (e == null)
map.put(s.getSortedNames(), s);
else
e.amount += s.amount;
}
At this point the map contains all unique Salary objects with the total amount for each.
You have few very helpful tools in Java. You can
split String into array defining separator like "jony,john".split(",") will give you array {"jony","john"}
sort data in arrays by Arrays.sort(arrayToSort)
compare if arrays are equal (contain same values with same order) by Arrays.equals(array1, array2) or by comparing its String representation using Arrays.toString(array)
use Maps (like HashMap) to hold pairs [key -> value]
With these you can solve your problem.
Tip: You can use Map like <String, Double> to count your data. As key (String) you can use sorted representation of names. If Map already contains some sorted representation of names then increase value stored under that key.

Sorting a HashMap with 2 fields

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.

Categories

Resources