I need to search a value in TreeMap with partial key
I tried with HashMap but its failing
TreeMap<String, BigDecimal> mapYr1 = new TreeMap<String, BigDecimal>();
mapYr1.put("abcdef",100.00);
Is it possible to retrieve value of 100.00 with something like below?
mapYr1.get("abcd");
Here I only know "abcd". I'm not sure "ef" part of key.
Not directly, but you can go over the entries and search for it:
public static BigDecimal findPartialKey(Map<String, BigDecimal> map, String search) {
return map.entrySet()
.stream()
.filter(e -> e.getKey().startsWith(search))
.map(Map.Entry::getValue)
.findFirst()
.orElse(null);
}
Note the using a stream like this, while (questionably) elegant, doesn't take advantage of the fact that the keys in a TreeMap are sorted, and may waste time looking for a matching key in a region that can't contain it. Using a good old-fashioned loop may be a bit clunkier, but in the general case, should perform a bit better:
public static BigDecimalfindPartialKey(SortedMap<String, BigDecimal> map, String search) {
Iterator<Map.Entry<String, Double>> iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String, Double> entry = iter.next();
String key = entry.getKey();
if (key.startsWith(search)) {
return entry.getValue();
}
if (key.compareTo(search) > 0) {
return null;
}
}
return null;
}
Related
Let's say I have the LinkedHashMap with some unknown data inside.
//==================
Map< Integer, String > map = new LinkedHashMap<>();
map.put(10, "C");
map.put(20, "C++");
map.put(50, "JAVA");
map.put(40, "PHP");
map.put(30, "Kotlin");
//=============
And I know just the key = 50;
I am wondering what is the best way to get the next element to the element that I have by this key (50)? This is not a multi-threaded application. I don't worry about thread-safety.
I don't like the way to iterate all keys through entrySet from the beginning.
It would be great to somehow get access to the next() of LinkedHashMaps Entry.
This is LinkedHashMap so it remembers the order of elements insertion.
public static Map.Entry<Integer, String> getNextEntry(LinkedHashMap<Integer, String> map, Integer key) {
List<Integer> keys = new ArrayList<>(map.keySet());
int index = keys.indexOf(key);
if (index < 0 || index >= keys.size() - 1)
return null;
int k = keys.get(index + 1);
return Map.entry(k, map.get(k));
}
Or you can use Iterator:
public static Map.Entry<Integer, String> getNextEntry(LinkedHashMap<Integer, String> map, Integer key) {
boolean found = false;
for (Map.Entry<Integer, String> entry : map.entrySet()) {
if (found)
return Map.entry(entry.getKey(), entry.getValue());
if (entry.getKey().intValue() == key)
found = true;
}
return null;
}
LinkedHashMap doesn't offer a functionality which would allow finding the next key or entry.
In case if you simply don't want to bother with managing iteration yourself manually, then sure you can alternate this process, but keep in mind that the iteration should happen somewhere anyway.
Stream API
Alternatively you can make use of the Stream API if you don't want to bother with loops.
public static Optional<Map.Entry<Integer, String>> getNextEntry(Map<Integer, String> map,
int previous) {
return map.entrySet().stream()
.dropWhile(entry -> entry.getKey() != previous) // discard the entries, until the target key has been encountered
.skip(1) // skip the entry with the target key
.findFirst(); // grab the next entry and return it as an Optional (because the next entry might not exist)
}
TreeMap
However, you would be able to navigate through the keys of the map if you were using a TreeMap.
TreeMap maintains a red-black tree under the hood, and it keep the entries in sorted order based on keys. And it offers various method like higherEntry(), higherKey().
NavigableMap<Integer, String> map = new TreeMap<>();
// populating the map
int key = 50;
Map.Entry<Integer, String> next = map.higherEntry(key);
I have a file that i get all the data and separate it into a HashMap.
The file looks something like this below.
Before the : is the key and after is the value
key1: 1
key2: 2
key3: 3
this is the code that puts the file data into the map ArrayList:
protected List<Map<String, String>> yaml_parse(BufferedReader filename) throws IOException{
String result;
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
while ((result = filename.readLine()) != null) {
Map<String, String> map = new HashMap<String, String>();
String key = result.substring(0, result.indexOf(":"));
String value = result.substring(result.lastIndexOf(":") + 2);
map.put(key, value);
list.add(map);
}
return list;
}
in another class where i call the function and println, this is the output
[{key1=1}, {key2=2}, {key3=3}]
So my Main question is, how do i get key1 and have it return its value?
I don't understand why you are creating a List of maps. A Map will let you put several key value pairs. Here is a way that would work:
protected Map<String, String> yaml_parse(BufferedReader filename) throws IOException{
String result;
Map<String, String> map = new HashMap<String, String>();
while ((result = filename.readLine()) != null) {
//keyValue[0] = key, keyValue[1] = value
String[] keyValue = result.split(": ");
map.put(keyValue[0], keyValue[1]);
}
return map;
}
And you would use it like this:
Map<String, String> map = yaml_parse("myFile.yaml");
String key1Value = map.get("key1"); //Stores key1's value into key1Value
I think you might be using the wrong data structure. From your question, it seems like you want a Map only, not a List of Maps.
You should look at changing your List<Map> to a Map. You can do this using:
Map<String, String> map = list.stream()
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
If you want to work with your current data structure, you can get the required value like this:
private Optional<String> getValue(List<Map<String, String>> list, String key) {
return list.stream()
.filter(m -> m.containsKey(key))
.map(m -> m.get(key))
.findFirst();
}
and use it as follows:-
Optional<String> value = getValue(list, "key2");
System.out.println(value.orElse(null));
So if you are interested in using java-8, if list of map contains any of entry with key as key1 will return the first entry value else it will return the default value
list.stream().flatMap(map->map.entrySet().stream().filter(entry->entry.getKey().equals("key1"))).findFirst()
.orElse(new AbstractMap.SimpleEntry("key1", "default value")).getValue();
Just by using normal for loop
for(Map<String, String> map : list) {
if(map.containsKey("key1")) {
result = map.get("key1");
break;
}
}
Are you sure this is the data structure you want?
A map can contain more than 1 key/value pair. Why not have a single hashmap here, containing all 3 key/value pairs, at which point, you can just do:
map.get("key1")
and it'll still be fast even if you have millions of these.
If you are making single-size maps and putting them into an arraylist because you want to preserve order, use LinkedHashMap. If you need to be capable of dealing with repeated keys, use guava's Multimap, or make a Map<String, List<String>>.
Is it possible for return all values of a HashMap if they're below a certain value? This is the Hash:
Map<String, Integer> StockIO = new HashMap<>();
The String being the stock item and Integer being the stock value.
I'm sure I'm missing something simple here.
This is the correct working and tested code using a jbutton click that then prints to a textarea:
private void OrderActionPerformed(java.awt.event.ActionEvent evt) {
Set<String> keys = new HashSet<>();
for(Map.Entry<String,Integer> entry: StockIO.entrySet())
{
if (entry.getValue() <= 10)
{
keys.add(entry.getKey());
Oresult.setText(entry.getKey());
}
}
}
I didn't get your question fully, but check this code below. May be it is what you want:
HashMap<String,Integer> jj=new HashMap<String, Integer>();
jj.put("A",10);
jj.put("B",20);
jj.put("c",30);
jj.put("Bd",50);
jj.put("Af",40);
jj.put("Bd",240);
jj.put("Ads",130);
jj.put("Bde",240);
jj.put("As",130);
jj.put("Bfe",210);
int threshold=100;
for(String key:jj.keySet()){
String stock_item=key;
Integer stock_value=jj.get(key);
if(stock_value<threshold)
System.out.println("Item:"+stock_item+" "+" Value:"+stock_value+"\n");
}`
Yes, but it isn't efficient. If you want ordering, use an ordered map, i.e. a TreeMap.
What you want is effectively filtering your collection of keys.
With this code, you get all the keys that have a value lower than or equal to a specific threshold.
public static Set<String> keysWithValuesBelowThreshold(Map<String,Integer> map, int threshold) {
Set<String> keys = new HashSet<>();
for(Map.Entry<String,Integer> entry: map.entrySet()) {
if (entry.getValue() <= threshold) {
keys.add(entry.getKey());
}
}
return keys;
}
With Java 8:
public static Set<String> keysWithValuesBelowThreshold(Map<String,Integer> map, int threshold) {
return map.entrySet().stream()
.filter(e -> e.getValue() <= threshold)
.map(Map.Entry::getKey)
.collect(Collectors.toSet());
}
What's the best way to iterate over the below two maps together? I want to compare two maps values which are strings and have to get the keys and values.
HashMap<String, String> map1;
HashMap<String, String> map2;
There really isn't a better option than
for (Map.Entry<String, String> entry1 : map1.entrySet() {
String key = entry1.getKey();
String value1 = entry1.getValue();
String value2 = map2.get(key);
// do whatever with value1 and value2
}
Depending on what exactly you're trying to do, there are several reasonable options:
Just compare the contents of two maps
Guava provides a Maps.difference() utility that gives you a MapDifference instance letting you inspect exactly what is the same or different between two maps.
Iterate over their entries simultaneously
If you just want to iterate over the entries in two maps simultaneously, it's no different than iterating over any other Collection. This question goes into more detail, but a basic solution would look like this:
Preconditions.checkState(map1.size() == map2.size());
Iterator<Entry<String, String>> iter1 = map1.entrySet().iterator();
Iterator<Entry<String, String>> iter2 = map2.entrySet().iterator();
while(iter1.hasNext() || iter2.hasNext()) {
Entry<String, String> e1 = iter1.next();
Entry<String, String> e2 = iter2.next();
...
}
Note there is no guarantee these entries will be in the same order (and therefore e1.getKey().equals(e2.getKey()) may well be false).
Iterate over their keys to pair up their values
If you need the keys to line up, iterate over the union of both maps' keys:
for(String key : Sets.union(map1.keySet(), map2.keySet()) {
// these could be null, if the maps don't share the same keys
String value1 = map1.get(key);
String value2 = map2.get(key);
...
}
My case if maps are the same sizes
IntStream.range(0, map1.size()).forEach(i -> map1.get(i).equals(map2.get(i));
You can do something like:
for (String key : map1.keySet()) {
if (map2.containsKey(key)) {
// do whatever
} else {
// map2 doesn't have entry with map1 key
}
}
I have this HashMap that I need to print out in ascending order according to the values contained in it (not the keys).
But the order when I print it out is seemingly random.
What's the best way to print it out in ascending value order?
Map<String, String> codes = new HashMap<String, String>();
codes.put("A1", "Aania");
codes.put("X1", "Abatha");
codes.put("C1", "Acathan");
codes.put("S1", "Adreenas");
In other words, the example above should print out as this:
A1, Aania
X1, Abatha
C1, Acathan
S1, Adreenas
You aren't going to be able to do this from the HashMap class alone.
I would take the Map<String, String> codes, construct a reverse map of TreeMap<String, String> reversedMap where you map the values of the codes Map to the keys (this would require your original Map to have a one-to-one mapping from key-to-value). Since the TreeMap provides Iterators which returns entries in ascending key order, this will give you the value/key combination of the first map in the order (sorted by values) you desire.
Map<String, String> reversedMap = new TreeMap<String, String>(codes);
//then you just access the reversedMap however you like...
for (Map.Entry entry : reversedMap.entrySet()) {
System.out.println(entry.getKey() + ", " + entry.getValue());
}
There are several collections libraries (commons-collections, Google Collections, etc) which have similar bidirectional Map implementations.
You'll need to make a list of the keys, sort them according to the corresponding values, then iterate over the sorted keys.
Map<String, String> map = getMyMap();
List<String> keys = new ArrayList<String>(map.keySet());
Collections.sort(keys, someComparator);
for (String key: keys) {
System.out.println(key + ": " + map.get(key));
}
As for what to use for someComparator, here are some handy, generic Comparator-creating routines I often find useful. The first one sorts by the values according to their natural ordering, and the second allows you to specify any arbitrary Comparator to sort the values:
public static <K, V extends Comparable<? super V>>
Comparator<K> mapValueComparator(final Map<K, V> map) {
return new Comparator<K>() {
public int compare(K key1, K key2) {
return map.get(key1).compareTo(map.get(key2));
}
};
}
public static <K, V>
Comparator<K> mapValueComparator(final Map<K, V> map,
final Comparator<V> comparator) {
return new Comparator<K>() {
public int compare(K key1, K key2) {
return comparator.compare(map.get(key1), map.get(key2));
}
};
}
It's time to add some lambdas:
codes.entrySet()
.stream()
.sorted(Comparator.comparing(Map.Entry::getValue))
.forEach(System.out::println);
the for loop of for(Map.Entry entry: codes.entrySet()) didn't work for me. Used Iterator instead.
Iterator<Map.Entry<String, String>> i = codes.entrySet().iterator();
while(i.hasNext()){
String key = i.next().getKey();
System.out.println(key+", "+codes.get(key));
}
you just need to use:
Map<>.toString().replace("]","\n");
and replaces the ending square bracket of each key=value set with a new line.
Java 8
map.entrySet().stream().sorted(Map.Entry.comparingByValue()).forEach(System.out::println);
Create a TreeMap<String,String>
Add each of the HashMap entries with the value as the key.
iterate the TreeMap
If the values are nonunique, you would need a list in the second position.
You can use a list of the entry set rather than the key set and it is a more natural choice given you are sorting based on the value. This avoids a lot of unneeded lookups in the sorting and printing of the entries.
Map<String, String> map = ...
List<Map.Entry<String, String>> listOfEntries = new ArrayList<Map.Entry<String, String>>(map.entrySet());
Collections.sort(listOfEntries, new SortByValueComparator());
for(Map.Entry<String, String> entry: listOfEntries)
System.out.println(entry);
static class SortByValueComparator implements Comparator<Map.Entry<String, String>> {
public int compareTo(Map.Entry<String, String> e1, Map.Entry<String, String> e2) {
return e1.getValue().compateTo(e2.getValue());
}
}
the simplest and shortest code i think is this:
public void listPrinter(LinkedHashMap<String, String> caseList) {
for(Entry entry:caseList.entrySet()) {
System.out.println("K: \t"+entry.getKey()+", V: \t"+entry.getValue());
}
}
The simplest solution would be to use a sorted map like TreeMap instead of HashMap.
If you do not have control over the map construction, then the minimal solution would be to construct a sorted set of keys. You don't really need a new map.
Set<String> sortedKeys = new TreeSet<String>();
sortedKeys.addAll(codes.keySet());
for(String key: sortedKeys){
println(key + ":" + codes.get(key));
}
Try:
try
{
int cnt= m.getSmartPhoneCount("HTC",true);
System.out.println("total count of HTC="+cnt);
}
catch (NoSuchBrandSmartPhoneAvailableException e)
{
// TODO Auto-generated catch
e.printStackTrace();
}
SmartPhone[] sp=new SmartPhone[4];
sp[0]=new SmartPhone(1,"HTC","desire","black",20000,10,true,true);
sp[1]=new SmartPhone(2,"samsung","grand","black",5000,10,false,true);
sp[2]=new SmartPhone(14,"google nexus","desire","black",2000,30,true,false);
sp[3]=new SmartPhone(13,"HTC","desire","white",50000,40,false,false);
while (itr.hasNext()) {
Vehicle vc=(Vehicle) itr.next();
if(vc.getVehicleType().equalsIgnoreCase(s)) {
count++;
}
}