Java Merge Nested HashMaps at the innermost/leaf level - java

Say I got 2 Key Value pairs:
String k1 = "a.b.c.d";
String v1 = "123";
String k2 = "a.b.c.d";
String v2 = "456";
And the desired output is:
a {
b {
c {
d = "123",
e = "456"
}
}
}
So, I've decided the split the keys by "." and form nested HashMaps and then trying to merge them when they have duplicate keys. However, it needs to merge at the leaf or innermost level instead of the outermost level.
This is the full code:
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class TestClass {
public static void main(String []args)
{
Map<String, Object> finalMap = new HashMap<>();
Map<String, Object> outerMap1 = new HashMap<>();
Map<String, Object> outerMap2 = new HashMap<>();
String k = "a.b.c.d";
String v = "123";
outerMap1 = createNestedStructure(k, v);
k = "a.b.c.e";
v = "456";
outerMap2 = createNestedStructure(k, v);
finalMap = Stream
.concat(outerMap1.entrySet().stream(),
outerMap2.entrySet().stream())
.collect(Collectors.toMap(Entry::getKey,
Entry::getValue, (a, b) -> {
String c = a.toString() + "\n" + b.toString();
return c;
}, HashMap::new));
System.out.println(finalMap.toString());
}
public static Map<String, Object> createNestedStructure(String k, String v)
{
String[] tokens = k.split("\\.");
Map<String, String> innerMap = new HashMap<>();
v = "\"" + v + "\"";
innerMap.put(tokens[tokens.length-1], v);
Map<String, Object> middleMap = new HashMap<>();
middleMap.put(tokens[tokens.length-2], innerMap);
for(int i=tokens.length-3; i>=0; i--)
{
Map<String, Object> middleMapTmp = new HashMap<>();
middleMapTmp.put(tokens[i], middleMap);
middleMap = middleMapTmp;
}
// Map<String, Object> outerMap = new HashMap<>();
// outerMap.put(tokens[0], middleMap);
// return outerMap;
return middleMap;
}
}
I'm not sure if this is the correct approach. So suggestions on better approaches are also welcome.

Not exactly sure about your specific problem, but you could simply insert the values into the same structure instead of merging them afterward. For example, you can make a recursive insert that creates the nested maps until it inserts your value on the last key part. If the nested map already exists it uses the existing one. Something like this could do the trick:
public static void main(String[] args) {
String k1 = "a.b.c.d";
String v1 = "123";
String k2 = "a.b.c.e";
String v2 = "456";
Map<String, Object> map = new HashMap<>();
recursiveInsert(map,k1, v1);
recursiveInsert(map,k2, v2);
System.out.println(map);
}
public static void recursiveInsert(Map<String, Object> map, String key, String value) {
int index = key.indexOf('.');
if (index == -1) {
map.put(key, value);
} else {
String subKey = key.substring(0, index);
map.putIfAbsent(subKey, new HashMap<>());
recursiveInsert((Map<String, Object>) map.get(subKey), key.substring(index + 1), value);
}
}
The output of this is what you requested:
{a={b={c={d=123, e=456}}}}

Related

Integer Optimization using OjAlgo objective function

I'm trying to use ojAlgo library in Java for Integer Optimization but I'm unable to provide it the objective function I intend to.
I'd like to minimize the function: (A - B.X)'(A - B.X), where A is a (n x 1) matrix, B is a (n x n) diagonal matrix and X is a (n x 1) matrix with the optimization variables. I want the result in X to consist of only integers .
I was able to set a different objective function which was to maximize B.X. How do I change it to (A - B.X)'(A - B.X)? Here is the code so far.
import org.apache.log4j.Logger;
import org.ojalgo.optimisation.Expression;
import org.ojalgo.optimisation.ExpressionsBasedModel;
import org.ojalgo.optimisation.Optimisation;
import org.ojalgo.optimisation.Variable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.InputMismatchException;
import java.util.List;
public class AllocationOptimization {
protected Logger log = Logger.getLogger(AllocationOptimization.class);
// This is the objective function, since weight() is assigned to it. How to change this objective function to what I want?
private List<Variable> makeVariables(HashMap<String, BigDecimal> matrixB) {
List<Variable> result = new ArrayList<>();
for (String assetName : matrixB.keySet()) {
result.add(new Variable(assetName).weight(matrixB.get(assetName)));
}
return result;
}
private ExpressionsBasedModel createExpressionModel(List<Variable> variables) {
final ExpressionsBasedModel model = new ExpressionsBasedModel();
for (Variable v : variables) {
model.addVariable(v);
}
return model;
}
private void addExpressionConstraints(ExpressionsBasedModel model, List<Variable> variables,
HashMap<String, BigDecimal> matrixB,
HashMap<String, BigDecimal> wantedAbsoluteSharesMap,
BigDecimal idealTotalPrice) {
Expression expression = model.addExpression("C1").upper(idealTotalPrice);
int i = 0;
for (String assetName : matrixB.keySet()) {
expression.set(variables.get(i), matrixB.get(assetName));
i += 1;
}
for (Variable v : variables) {
long absShares = wantedAbsoluteSharesMap.get(v.getName()).longValue();
v.lower((long) Math.max(0, 0.8 * absShares)).upper((long) Math.max(Math.max(0, 1.2 * absShares), 5));
}
}
private void setIntegerSolving(ExpressionsBasedModel model) {
for (Variable v : model.getVariables()) {
v.setInteger(true);
}
}
private HashMap<String, Long> getIntegerOptimizationResult(ExpressionsBasedModel model, HashMap<String, BigDecimal> matrixB) {
Optimisation.Result result = model.maximise();
return prepareResult(result, matrixB);
}
private HashMap<String, Long> prepareResult(Optimisation.Result result, HashMap<String, BigDecimal> matrixB) {
int i = 0;
HashMap<String, Long> optimizedResult = new HashMap<>();
BigDecimal sumAssetPrices = new BigDecimal("0.0");
for (String assetName : matrixB.keySet()) {
long sharesCount = result.get(i).longValue();
log.debug(assetName + ": " + sharesCount);
optimizedResult.put(assetName, sharesCount);
sumAssetPrices = sumAssetPrices.add(matrixB.get(assetName).multiply(BigDecimal.valueOf(sharesCount)));
i += 1;
}
log.debug("Total assets value after converting shares to integer numbers: " + sumAssetPrices);
return optimizedResult;
}
public HashMap<String, Long> optimizeSharesCount(HashMap<String, BigDecimal> constraint1,
HashMap<String, BigDecimal> matrixB,
BigDecimal constraint2) throws InputMismatchException {
List<Variable> variableList = makeVariables(matrixB);
ExpressionsBasedModel model = createExpressionModel(variableList);
addExpressionConstraints(model, variableList, matrixB, constraint1, constraint2);
setIntegerSolving(model);
HashMap<String, Long> resultMap = getIntegerOptimizationResult(model, matrixB);
return resultMap;
}
private HashMap<String, BigDecimal> createWantedAbsoluteSharesTest1() {
HashMap<String, BigDecimal> absShares = new HashMap<>();
absShares.put("NFLX", new BigDecimal("2"));
absShares.put("MSFT", new BigDecimal("4"));
absShares.put("GOOG", new BigDecimal("0"));
absShares.put("AAPL", new BigDecimal("25"));
return absShares;
}
private HashMap<String, BigDecimal> createAssetPricesMapTest1() {
HashMap<String, BigDecimal> assetPrices = new HashMap<>();
assetPrices.put("NFLX", new BigDecimal("601.06"));
assetPrices.put("MSFT", new BigDecimal("296.75"));
assetPrices.put("GOOG", new BigDecimal("2843.78"));
assetPrices.put("AAPL", new BigDecimal("149.07"));
return assetPrices;
}
public static void main(String[] args) {
AllocationOptimization allocationOptimization = new AllocationOptimization();
// For testing
HashMap<String, BigDecimal> constr1 = allocationOptimization.createWantedAbsoluteSharesTest1();
HashMap<String, BigDecimal> matrixB = allocationOptimization.createAssetPricesMapTest1();
BigDecimal constr2 = new BigDecimal("5348.25");
HashMap<String, Long> optimizedResult = null;
try {
optimizedResult = allocationOptimization.optimizeSharesCount(constr1, matrixB, constr2);
} catch (Exception e) {
e.printStackTrace();
}
assert optimizedResult != null;
allocationOptimization.log.info("optimizedResult size: " + optimizedResult.size());
}
}
You assigned weights to the Variable:s. That makes them part of the objective function. You can also assign weights to Expression:s. Anything/everything that has a weight is summed up to form the objective function.
Expression objective = model.addExpression("Whole Objective").weight(BigDecimal.ONE);
for (Variable variableR : variables) {
objective.set(variableR, linearParameter);
for (Variable variableC : variables) {
objective.set(variableR, variableC, quadraticParameter);
}
}
Is equivalent to:
Expression objective = model.addExpression("Objective Part").weight(BigDecimal.ONE);
for (Variable variableR : variables) {
variableR.weight(linearParameter);
for (Variable variableC : variables) {
objective.set(variableR, variableC, quadraticParameter);
}
}
I modified the objective function and added necessary constraints, following #apete's comments. Posting my solution here for others.
private List<Variable> makeVariables(HashMap<String, BigDecimal> matrixB) {
List<Variable> result = new ArrayList<>();
for (String assetName : matrixB.keySet()) {
result.add(new Variable(assetName));
}
return result;
}
private ExpressionsBasedModel createObjective(ExpressionsBasedModel model, List<Variable> variables,
HashMap<String, BigDecimal> matrixA,
HashMap<String, BigDecimal> matrixB) {
// Anything and everything with that has a weight is summed up to form the objective function
Expression objective = model.addExpression("Objective function").weight(BigDecimal.ONE);
for (Variable variable : variables) {
String assetName = variable.getName();
objective.set(variable, new BigDecimal("-2").multiply(matrixA.get(assetName)).multiply(matrixB.get(assetName)));
objective.set(variable, variable, matrixB.get(assetName).pow(2));
}
return model;
}
private void addExpressionConstraints(ExpressionsBasedModel model, List<Variable> variables,
HashMap<String, BigDecimal> matrixB,
HashMap<String, BigDecimal> wantedAbsoluteSharesMap,
HashMap<String, BigDecimal> matrixA,
BigDecimal idealTotalPrice, BigDecimal accountBalance) {
Expression expression1 = model.addExpression("C1").upper(idealTotalPrice);
for (Variable variable : variables) {
expression1.set(variable, matrixB.get(variable.getName()));
}
for (Variable v : variables) {
// No negative values constraint
v.lower(0);
}
// This constraint is used to compensate for the constants arising in the quadratic objective function
BigDecimal sumSquaresUserAllocation = new BigDecimal("0.0");
for (String assetName : this.assetsList) {
sumSquaresUserAllocation = sumSquaresUserAllocation.add(matrixA.get(assetName).pow(2));
}
Expression expression2 = model.addExpression("C2").upper(new BigDecimal("1.01").multiply(sumSquaresUserAllocation.multiply(new BigDecimal("-1"))));
expression2.lower(new BigDecimal("0.99").multiply(sumSquaresUserAllocation.multiply(new BigDecimal("-1"))));
for (Variable variable : variables) {
String assetName = variable.getName();
expression2.set(variable, new BigDecimal("-2").multiply(matrixA.get(assetName)).multiply(matrixB.get(assetName)));
expression2.set(variable, variable, matrixB.get(assetName).pow(2));
}
}
Finally, instead of using the model.maximise() function, I used model.minimise() to minimize the objective function.

How can I not overwrite values via putAll() but instead add to the current value?

Suppose I have two hash maps:
HashMap <String, Integer> h1;
h1.put("hi", 30);
h1.put("hi2",20);
h1.put("hi3",10);
h1.put("hi4",20);
HashMap <String, Integer> h2;
h2.put("hi", 20);
h2.put("hi2", 20);
h2.put("hi3", 20);
h2.put("hi4", 20);
My question is, if I do the following
h2.putAll(h1);
How could I update the values of h2 to be the sum, instead of just overwriting it? That is I want
[{"hi"=50}]
[{"hi2"=40}]
[{"hi3"=30}]
[{"hi4"=40}]
Instead of this
[{"hi"=30}]
[{"hi2"=20}]
[{"hi3"=10}]
[{"hi4"=20}]
Note: no functional constructs (including lambdas) and external libraries are allowed
You can use merge method for that:
h1.forEach((key, value) -> h2.merge( key, value, Integer::sum));
System.out.println(h2);
The old fashion way:
for(String key : h1.keySet()){
Integer v1 = h1.get(key);
Integer v2 = h2.get(key);
h2.put(key, (v2 == null) ? v1 : v1 + v2);
}
System.out.println(h2);
In traditional Java (before functional constructs), you would just iterate over the map and get the values from the other map
Map<String, Integer> h1 = new HashMap<>();
h1.put("hi", 30);
Map<String, Integer> h2 = new HashMap<>();
h2.put("hi", 20);
for (Map.Entry<String, Integer> entry : h2.entrySet()) {
String key = entry.getKey();
Integer toAdd = h1.get(key);
if (toAdd != null) {
entry.setValue(entry.getValue() + toAdd);
}
}
System.out.println("h1 = " + h1);
System.out.println("h2 = " + h2);
Which prints
h1 = {hi=30}
h2 = {hi=50}
To go further, if the expected result should be that h2 should also contain every non-matching key from h1, then you can use the following
Map<String, Integer> h1 = new HashMap<>();
h1.put("hi", 30);
h1.put("hii", 40);
Map<String, Integer> h2 = new HashMap<>();
h2.put("hi", 20);
for (Map.Entry<String, Integer> entry : h1.entrySet()) {
String key = entry.getKey();
Integer value = entry.getValue();
Integer toPossiblyMerge = h2.get(key);
if (toPossiblyMerge == null) {
h2.put(key, value);
} else {
h2.put(key, value + toPossiblyMerge);
}
}
System.out.println("h1 = " + h1);
System.out.println("h2 = " + h2);
Which prints
h1 = {hi=30, hii=40}
h2 = {hi=50, hii=40}
You can merge the two maps as shown below:
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map<String, Integer> h1 = new HashMap<>();
h1.put("hi", 30);
Map<String, Integer> h2 = new HashMap<>();
h2.put("hi", 20);
Map<String, Integer> h3 = new HashMap<>(h1);
h2.forEach(
(key, value) -> h3.merge(key, value, (v1, v2) -> v1 + v2)
);
System.out.println(h3);
}
}
Output:
{hi=50}
Non-Lambda solution:
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
public class Main {
public static void main(String[] args) {
Map<String, Integer> h1 = new HashMap<>();
h1.put("hi", 30);
Map<String, Integer> h2 = new HashMap<>();
h2.put("hi", 20);
Map<String, Integer> h3 = new HashMap<>(h1);
for (Entry<String, Integer> entry : h2.entrySet()) {
String key = entry.getKey();
h3.put(key, entry.getValue() + h1.getOrDefault(key, 0));
}
System.out.println(h3);
}
}
Output:
{hi=50}

How to flatten an array of dictionaries in Java?

I am working on below problem where I need to flatten array of dicts:
For example- Below is an input:
[
{'a':
{'b':
{'c':
{'d':'e'}
}
}
},
{'a':{'b':{'c':{'d':{'e':'f'}}}}},
{'a':'b'}
]
And the output will be:
[
{'a_b_c_d':'e'},
{'a_b_c_d_e':'f'},
{'a':'b'}
]
Below is what I was able to come up with. Is there any better way to solve this problem?
private static List<Map<String, String>> flatDictionary(final List<Map<String, Object>> input) {
List<Map<String, String>> listHolder = new ArrayList<>();
if(input == null || input.isEmpty()) {
return listHolder;
}
for(Map<String, Object> mapHolder : input) {
Map<String, String> m = new HashMap<>();
StringBuilder sb = new StringBuilder();
Map<String, String> output = helper(mapHolder, sb, m);
listHolder.add(output);
}
return listHolder;
}
private static Map<String, String> helper(final Map<String, Object> map, final StringBuilder sb, final Map<String, String> output) {
String mapValue = null;
for(Map.Entry<String, Object> holder : map.entrySet()) {
String key = holder.getKey();
Object value = holder.getValue();
if(value instanceof Map) {
sb.append(key).append("_");
helper((HashMap<String, Object>) value, sb, output);
} else if(value instanceof String) {
sb.append(key);
mapValue = (String) value;
}
output.put(sb.toString(), mapValue);
}
return output;
}
I would use recursion.
First define a method to flatten a single Map
public static void flatten(final String keyPrefix, final Map<String, Object> input, final Map<String, Object> output) {
for (final Map.Entry<String, Object> e : input.entrySet()) {
final var key = keyPrefix.isBlank() ? e.getKey() : keyPrefix + "_" + e.getKey();
if (e.getValue() instanceof Map) {
// if the nested Map is of the wrong type bad things may happen
flatten(key, (Map<String, Object>) e.getValue(), output);
} else {
output.put(key, e.getValue());
}
}
}
NB: This makes no attempt to deal with duplicate keys.
Usage:
public static void main(final String[] args) throws InterruptedException {
final var data = Map.of(
"A", Map.of("a", "Expect A_a"),
"B", Map.of("b1", Map.of(
"bb1", "expect B_b1_bb1",
"bb2", "expect B_b1_bb2"
)),
"C", "Expect C");
final var output = new HashMap<String, Object>();
flatten("", data, output);
output.forEach((k, v) -> System.out.printf("%s -> %s%n", k, v));
}
Output:
C -> Expect C
A_a -> Expect A_a
B_b1_bb2 -> expect B_b1_bb2
B_b1_bb1 -> expect B_b1_bb1
Now, simply define a method that loops to take your List
public static final Map<String, Object> flattenAll(final List<Map<String, Object>> input) {
final var output = new HashMap<String, Object>();
input.forEach(map -> flatten("", map, output));
return output;
}
NB: This makes no attempt to deal with duplicate keys.

Need a Fresh pair of Eyes to Work Out the Logic Behind Comparing Values in a Map of Maps

Problem
Data is in the format:
Map<String, Map<String, Integer>>
Which looks something like this:
{"MilkyWay": {"FirstStar" : 3, "SecondStar" : 9 .... }, "Andromeda": {"FirstStar" : 10, "SecondStar" : 9 .... } }
I want to compare the Star values in a quick loop, so I'd like to compare the integer value of FirstStar in MilkyWay and Andromeda and have it return true or falseif the values are the same or not. Since this Map of Maps is huge.
My Attempt
I'd like to do it something like:
//GalaxyMap<String, <Map<String, Integer>>
for (Map<String, Integer> _starMap : GalaxyMap.values())
{
for (String _starKey : _starMap.keySet()){
//Can't quite think of the correct logic... and I'm tired...
}
}
I'd like to keep it as short as possible... I've been staring at this for a while and I'm going in circles with it.
EDIT
Outer keys differ, Inner keys are the same
Also since this is a response from a server, I don't know the size it's going to be
Why does this need to be a map. If you're always using "FirstStar", "SecondStar" etc, as your keys, then why not make it a list instead..
Map<String, List<Integer>>
Then you can do something like:
public boolean compareGalaxyStar(String galaxyName, String otherGalaxyName, int star) {
List<Integer> galaxyStars = galaxyMap.get(galaxyName);
List<Integer> otherGalaxyStars = galaxyMap.get(otherGalaxyName);
return galaxyStars.get(star) == otherGalaxyStars.get(star);
}
NOTE: You need to do some validation to make sure the input is correct.
To implement this for all stars, it is not much different.
if(galaxyStars.size() == otherGalaxyStars.size()) {
for(int x = 0; x < galaxyStars.size(); x++) {
// Perform your comparisons.
if(galaxyStars.get(x) != otherGalaxyStars.get(x)) {
// Uh oh, unequal.
return false;
}
}
}
If the structure of the inner maps also could differ, you should do something like that:
static boolean allStarValuesEqual(Map<String, Map<String, Integer>> galaxies) {
Map<String, Integer> refStars = null;
for (Map<String, Integer> galaxy : galaxies.values()) {
if (refStars == null) {
refStars = galaxy;
} else {
for (Entry<String, Integer> currentStar : galaxy.entrySet()) {
if (!currentStar.getValue().equals(refStars.get(currentStar.getKey()))) {
return false;
}
}
}
}
return true;
}
Please check below program along with output:
package com.test;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class CompareMapValues {
private final static String FS = "FirstStar";
private final static String SS = "SecondStar";
private final static String MW = "MilkyWay";
private final static String A = "Andromeda";
public static void main(String[] args) {
Map> map = new HashMap>();
Map innerMap1 = new HashMap();
innerMap1.put(FS, 3);
innerMap1.put(SS, 9);
Map innerMap2 = new HashMap();
innerMap2.put(FS, 10);
innerMap2.put(SS, 9);
map.put(MW, innerMap1);
map.put(A, innerMap2);
Set set = map.keySet();
for(String s: set) {
Map outerMap = map.get(s);
Set set2 = map.keySet();
for(String s2: set2) {
Map innerMap = map.get(s2);
if(!s2.equals(s)) {
Set set3 = outerMap.keySet();
for(String s3: set3) {
int i1 = outerMap.get(s3);
Set set4 = innerMap.keySet();
for(String s4: set4) {
int i2 = innerMap.get(s3);
if(s3.equals(s4) && i1==i2) {
System.out.println("For parent " + s + " for " + s3 + " value is " + i1);
}
}
}
}
}
}
}
}
//Output:
//For parent Andromeda for SecondStar value is 9
//For parent MilkyWay for SecondStar value is 9
Hope this helps.

Sorting by values in HashMap class using Java

I'm trying to get results HashMap sorted by value.
This is HashMap's keys and values:
map.put("ertu", 5);
map.put("burak", 4);
map.put("selin", 2);
map.put("can", 1);
I try to get results like this:
1 = can
2 = selin
4 = burak
5 = ertu
Here is my code:
import java.util.*;
public class mapTers {
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("ertu", 5);
map.put("burak", 4);
map.put("selin", 2);
map.put("can", 1);
Integer dizi[] = new Integer[map.size()];
Set anahtarlar = map.keySet();
Iterator t = anahtarlar.iterator();
int a = 0;
while (t.hasNext()) {
dizi[a] = map.get(t.next());
a++;
}
Arrays.sort(dizi);
for (int i = 0; i < map.size(); i++) {
while (t.hasNext()) {
if (dizi[i].equals(map.get(t.next()))) {
System.out.println(dizi[i] + " = " + t.next());
}
}
}
}
}
You can sort the entries as follows (but note this won't sort the map itself, and also HashMap cannot be sorted) -
List<Map.Entry<String, Integer>> entryList = new ArrayList<Map.Entry<String, Integer>>(map.entrySet());
Collections.sort(entryList, new Comparator<Map.Entry<String, Integer>>() {
#Override
public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
return o1.getValue().compareTo(o2.getValue());
}
});
Every time that you call t.next(), the iterator's pointer is moved forward. Eventually, the iterator reaches the end. You need to reset the iterator. Also, calling t.next() twice moves the pointer twice.
Here's my solution:
import java.util.*;
public class mapTers
{
public static void main(String[] args)
{
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("ertu", 5);
map.put("burak", 4);
map.put("selin", 2);
map.put("can", 1);
Integer dizi[] = new Integer[map.size()];
Set anahtarlar = map.keySet();
Iterator t = anahtarlar.iterator();
int a = 0;
while (t.hasNext())
{
dizi[a] = map.get(t.next());
a++;
}
Arrays.sort(dizi);
for (int i = 0; i < map.size(); i++)
{
t = anahtarlar.iterator();
while (t.hasNext())
{
String temp = (String)t.next();
if (dizi[i].equals(map.get(temp)))
{
System.out.println(dizi[i] + " = " + temp);
}
}
}
}
}
You cannot do that from a Map. At least not directly.
Retrieve the keys/entries, get all the map data in a more suitable structure (hint: a class that encapsulates both attributes and is is stored in a sortable (hint2: SortedSet, List)) and sort.
Do not forget to extend Comparable (and implement compareTo) or, otherwise, create a Comparator.
This is one of the solutions take from: https://stackoverflow.com/a/13913206/1256583
Just pass in the unsorted map, and you'll get the sorted one.
private static Map<String, Integer> sortByComparator(Map<String, Integer> unsortMap, final boolean order) {
List<Entry<String, Integer>> list = new LinkedList<Entry<String, Integer>>(unsortMap.entrySet());
// Sorting the list based on values
Collections.sort(list, new Comparator<Entry<String, Integer>>() {
public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
if (order) {
return o1.getValue().compareTo(o2.getValue());
}
else {
return o2.getValue().compareTo(o1.getValue());
}
}
});
// Maintaining insertion order with the help of LinkedList
Map<String, Integer> sortedMap = new LinkedHashMap<String, Integer>();
for (Entry<String, Integer> entry : list) {
sortedMap.put(entry.getKey(), entry.getValue());
}
return sortedMap;
}
To print, do a simple iteration over the entry set:
public static void printMap(Map<String, Integer> map) {
for (Entry<String, Integer> entry : map.entrySet()) {
System.out.println("Key : " + entry.getKey() + " Value : "+ entry.getValue());
}
}
You probably have the wrong data structure for this problem. Either:
Reverse the map so the integers are the keys and the words the values and make the map a SortedMap, or
Use a bidirectional map as provided by libraries like Google Guava.
Reversed Map
private final SortedMap<Integer, String> TRANSLATIONS;
static {
SortedMap<Integer, String> map = new TreeMap<>();
map.put(1, "can");
// ...
TRANSLATIONS = Collections.unmodifiableSortedMap(map);
}
Guava BiMap
private final BiMap TRANSLATIONS =
new ImmutableBiMap.Builder<String, Integer>()
.put("ertu", 5);
.put("burak", 4);
.put("selin", 2);
.put("can", 1);
.build();
Then, iterate over a sorted version of the key set or value set as needed. For example,
TRANSLATIONS.inverse.get(4); // "burak"
I'm just curious. What language are your strings in?

Categories

Resources