Get random value from HashMap - random

I want to get random value of HashMap, but only from one key.
This is how i build my HashMap. Every Key has multiple values.
ArrayList<HashMap<String, String>> items = new ArrayList<HashMap<String, String>>();
for (.....) {
// creating new HashMap
HashMap<String, String> map = new HashMap<String, String>();
Element e = (Element) nl.item(i);
map.put(KEY_1, parser.getValue(e, KEY_1));
map.put(KEY_2, parser.getValue(e, KEY_2));
// adding HashList to ArrayList
items.add(map);
}
So key "KEY_1" has multiple values so do "KEY_2".
Now i want to get random value using key "KEY_1". How to do that ?
EDIT: I think i know where is problem, although dont know yet how to fix that.
Problem is defining size(); I need somehow get size not from all HashMap items like "items.size();" but something more similar to "items.KEY_1.size();"
With this code getting NullPointerException
int index = random.nextInt(items.size());
HashMap<String, String> randomitem = new HashMap<String, String>();
randomitem = items.get(index);
System.out.println(randomitem.get(KEY_1));
With this code im able to get value not random:
int index = 2;
HashMap<String, String> randomitem = new HashMap<String, String>();
randomitem = items.get(index);
System.out.println(randomitem.get(KEY_1));
EDIT: With this code i can get random values but i get values from all keys. How to get values only from one key ?
Random rand = new Random();
indexx = rand.nextInt(items.size());
System.out.println(items.get(indexx));
Solved With this code i can get random value from certain key.
Random rand = new Random();
indexx = rand.nextInt(items.size());
HashMap<String, String> randomitems = items.get(indexx);
System.out.println(randomitems.get(KEY_1));

Related

How to collect map from the Set of objects that has a list using Collectors.toMap

I have class Element with a list, my intended output is like this:
Map<String , List<Element>>
{
1 = [Element3, Element1],
2 = [Element2, Element1],
3 = [Element2, Element1], 4=[Element2]
}
And my input is set of element objects, I used forEach to get the desired outcome, but I'm looking for how to collect it using collectors.toMap. Any inputs are much appreciated
Set<Element> changes = new HashSet();
List<String> interesetList = new ArrayList();
interesetList.add("1");
interesetList.add("2");
interesetList.add("3");
Element element = new Element(interesetList);
changes.add(element);
interesetList = new ArrayList();
interesetList.add("2");
interesetList.add("3");
interesetList.add("4");
element = new Element(interesetList);
changes.add(element);
Map<String, List<Element>> collect2 = new HashMap();
changes.forEach(element -> {
element.getInterestedList().forEach(tracker -> {
collect2.compute(tracker, ( key , val) -> {
List<Element> elementList = val == null ? new ArrayList<Element>() : val;
elementList.add(Element);
return elementList;
});
});
});
class Element {
List<String> interestedList;
static AtomicInteger sequencer = new AtomicInteger(0);
String mName;
public Element(List<String> aList) {
interestedList = aList;
mName = "Element" + sequencer.incrementAndGet();
}
public List<String> getInterestedList() {
return interestedList;
}
#Override
public String toString() {
return mName;
}
}
You can do it by using Collectors.groupingBy instead of Collectors.toMap, along with Collectors.mapping, which adapts a collector to another collector:
Map<String, List<Element>> result = changes.stream()
.flatMap(e -> e.getInterestedList().stream().map(t -> Map.entry(t, e)))
.collect(Collectors.groupingBy(
Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue, Collectors.toList())));
You need to use the Stream.flatMap method first and then pair the elements of the inner lists with the current Element instance. I did this via the new Java 9's Map.entry(key, value) method. If you're not on Java 9 yet, you could change it to new AbstractMap.SimpleEntry<>(key, value).
After flatmapping, we need to collect instances of Map.Entry. So I'm using Collectors.groupingBy to classify entries by key (where we had previously stored each element of the inner lists, aka what you call tracker in your code). Then, as we don't want to have instances of List<Map.Entry<String, Element>> as the values of the map, we need to transform each Map.Entry<String, Element> of the stream to just Element (that's why I'm using Map.Entry::getValue as the first argument of Collectors.mapping). We also need to specify a downstream collector (here Collectors.toList()), so that the outer Collectors.groupingBy collector knows where to place all the adapted elements of the stream that belong to each group.
A shorter and surely more efficient way to do the same (similar to your attempt) could be:
Map<String, List<Element>> result = new HashMap<>();
changes.forEach(e ->
e.getInterestedList().forEach(t ->
result.computeIfAbsent(t, k -> new ArrayList<>()).add(e)));
This uses Map.computeIfAbsent, which is a perfect fit for your use case.

Convert List to Map using streams

This question is partially answered here.
My map will have trade Ids grouped by trade Type. This link gives me Trades grouped by tradeType. I know I can further manipulate it to get desired result, but just wondering if its possible in one go.
Here is my code.
public static void main(String[] args) {
Trade trade1 = new Trade(1, TradeStatus.NEW, "type1",1);
Trade trade2 = new Trade(2, TradeStatus.FAILED, "type2",1);
Trade trade3 = new Trade(3, TradeStatus.NEW, "type1",1);
Trade trade4 = new Trade(4, TradeStatus.NEW, "type3",1);
Trade trade5 = new Trade(5, TradeStatus.CHANGED, "type2",1);
Trade trade6 = new Trade(6, TradeStatus.EXPIRED, "type1",2);
List<Trade> list = new ArrayList<>();
list.add(trade1);
list.add(trade2);
list.add(trade3);
list.add(trade4);
list.add(trade5);
list.add(trade6);
Map<String, List<Trade>> result =
list.stream().collect(Collectors.groupingBy(Trade::getTradeType));
System.out.println(result);//prints Trades grouped by trade type
Map<String, List<String>> unvaluedtradesMap = new HashMap<>();
for (Trade trade : list) {
String tradeType = trade.getTradeType();
if(unvaluedtradesMap.containsKey(trade.getTradeType())){
List<String> unValuedTrades = unvaluedtradesMap.get(tradeType);
unValuedTrades.add(trade.getId());
unvaluedtradesMap.put(tradeType, unValuedTrades);
}else{
unvaluedtradesMap.put(tradeType, Lists.newArrayList(trade.getId()));
}
}
System.out.println(unvaluedtradesMap);//prints TradeIDS grouped by trade type
}
You can do this by chaining a mapping collector to groupingBy :
Map<String, List<String>> unvaluedtradesMap
= list.stream().collect(Collectors.groupingBy(Trade::getTradeType,
Collectors.mapping(Trade::getId,
Collectors.toList())));

Java 8 sort Map<String, List<Double>>

How to sort a Map > according to average of all the values in the list using Java8 streams?
I couldn't figure out how to collect the sorted map to another instance of map. Thanks for the help in advance.
Here is the code that I tried
Map<String,List<Double>> map = new HashMap<String,List<Double>>();
LinkedList<Double> list1 = new LinkedList<Double>(Arrays.asList(12.5,45.67));
map.put("1",list1);
LinkedList<Double> list2 = new LinkedList<Double>(Arrays.asList(13.5,49.67));
map.put("2", list2);
LinkedList<Double> list3 = new LinkedList<Double>(Arrays.asList(10.5,9.67));
map.put("3", list3);
LinkedList<Double> list4 = new LinkedList<Double>(Arrays.asList(1.5,40.67));
map.put("4", list4);
map.entrySet().stream().sorted(new Comparator<Map.Entry<String, List<Double>>>() {
#Override
public int compare(Entry<String, List<Double>> arg0, Entry<String, List<Double>> arg1) {
return (int)(((LinkedList<Double>)arg1.getValue()).stream().mapToDouble(Double::doubleValue).sum() - ((LinkedList<Double>)arg0.getValue()).stream().mapToDouble(Double::doubleValue).sum());
}
});
System.out.println(map);
The output I get is still the same Map with out sorting. The expected output here is a map with the entries in this order
<"2", list2>
<"1", list1>
<"4", list4>
<"3", list3>
Edit:
Here is the solution I got to
Map<String,List<Double>> map = new HashMap<String,List<Double>>();
LinkedList<Double> list1 = new LinkedList<Double>(Arrays.asList(12.5,45.67));
map.put("1",list1);
LinkedList<Double> list2 = new LinkedList<Double>(Arrays.asList(13.5,49.67));
map.put("2", list2);
LinkedList<Double> list3 = new LinkedList<Double>(Arrays.asList(10.5,9.67));
map.put("3", list3);
LinkedList<Double> list4 = new LinkedList<Double>(Arrays.asList(1.5,40.67));
map.put("4", list4);
LinkedHashMap<String,List<Double>> orderedMap = new LinkedHashMap<String,List<Double>>();
Iterator<Entry<String, List<Double>>> iterator = map.entrySet().stream().sorted(new Comparator<Map.Entry<String, List<Double>>>() {
#Override
public int compare(Entry<String, List<Double>> arg0,
Entry<String, List<Double>> arg1) {
return (int)((((LinkedList<Double>) arg1.getValue()).stream().mapToDouble(Double::doubleValue).sum() - ((LinkedList<Double>)arg0.getValue()).stream().mapToDouble(Double::doubleValue).sum()));
}
}).iterator();
while(iterator.hasNext()){
Entry<String, List<Double>> next = iterator.next();
orderedMap.put(next.getKey(), next.getValue());
}
System.out.println(orderedMap);
I am not happy with this solution. Is there a precise and better way of doing this?
Your comparator doesn’t do the job you want, or at least not always. It works only if all the lists have the same size because you are comparing the sum not the average values for each list. I created a new Comparator based on lists average values and simplified the code. Below is my code:
Comparator<Map.Entry<String,List<Double>>> byAverange =
(Entry<String,List<Double>> o1, Entry<String,List<Double>> o2)->
{
return ((Double)o2.getValue().stream().mapToDouble(a -> a).average().getAsDouble())
.compareTo(
o1.getValue().stream().mapToDouble(a -> a).average().getAsDouble());
};
LinkedHashMap<String, List<Double>> ordered = new LinkedHashMap<>();
map.entrySet().stream().sorted(byAverange).forEach(entry -> ordered.put(entry.getKey(), entry.getValue()));
System.out.println(ordered);
output:
{2=[13.5, 49.67], 1=[12.5, 45.67], 4=[1.5, 40.67], 3=[10.5, 9.67]}
hope this can help.

Morse code conversion on how to return a method

Please pardon me for my weak porgramming ability. I'm trying to write a method converting english to morse code. As you can see, I use hashmap to store the equivalant and then convert it and stored the morse code into the variable 'result'. My concern is I can't return the variable 'result' outside of the loop. If i return 'dataInput', isn't it just returning the original input? How can I return the correct result?
public static String morseCode(String dataInput)
{
Map<String, String> morseCode = new HashMap<String, String>();
morseCode.put("a", ".-");
morseCode.put("b", "-...");
morseCode.put("c", "-.-.");
for (int i = 0; i<dataInput.length(); i++)
{
String result = (String)morseCode.get(dataInput.charAt(i)+"");
//convert input data into morse code
}
return dataInput;
}
Try like this:
import java.lang.StringBuffer; //at the top
Map morseCode = new HashMap();
morseCode.put("a", ".-");
morseCode.put("b", "-...");
morseCode.put("c", "-.-.");
StringBuffer buff = new StringBuffer();
for (int i = 0; i<dataInput.length(); i++)
{
String result = (String)morseCode.get(dataInput.charAt(i));
//convert input data into morse code
buff.append(result+" ");
}
return buff.toString();
}

Custom compare dictionaries linq

I've two dictionaries as following:
Dictionary 1:
Dictionary<string, string> dict1 = new Dictionary<string, string>();
request.Add("key1", "value1");
request.Add("key2", "value2");
request.Add("key3", "value3");
Dictionary 2 :
Dictionary<string, string> request = new Dictionary<string, string>();
request.Add("key1", "value1");
request.Add("key2", "value2");
I need to compare above two dictionaries using LINQ query with condition:
1) All keys in dict2 should match with keys in dict1
2) The matched keys should have equivalent value
3) Even if the value of key2 in dict2 is empty, it should match
Help on above in appreciated. Thanks in advance.
Regards,
Sachin
You could use the Contains method and provide a custom IEqualityComparer, but an easier way would be to use Any():
var dict1 = new Dictionary<string, string>
{
{"key1", "value1"},
{"key2", "value2"},
{"key3", "value3"}
};
var dict2 = new Dictionary<string, string>
{
{"key1", "value1"},
{"key2", "value2"}
};
dict2.All(k2 =>
dict1.Any(k1 => k1.Key == k2.Key &&
(String.IsNullOrEmpty(k2.Value) || k1.Value == k2.Value)))
I guess with empty you mean null or an empty string, hence I used String.IsNullOrEmpty. If you want to just check for null, do a simple k2.Value == null instead.

Resources