I have a program that takes the number of instances of a character in a string and then puts them into a HashMap. I have it working, but how do I alphabetize the HashMap. Here is my code:
import java.util.*;
import java.lang.*;
import javax.swing.JOptionPane;
import java.io.*;
public class CharacterCount
{
public static void main(String args[])
{
{
String s = JOptionPane.showInputDialog("Enter in any text.");
String str = s.replaceAll("[., ]", "");
String[] splitted = str.split("");
HashMap hm = new HashMap();
for (int i = 0; i < splitted.length; i++) {
if (!hm.containsKey(splitted[i])) {
hm.put(splitted[i], 1);
} else {
hm.put(splitted[i], (Integer) hm.get(splitted[i]) + 1);
}
}
for (Object word : hm.keySet()) {
if (word.equals("")) {
System.out.println("Spaces: " + (Integer) hm.get(word));
}
else {
System.out.println(word + ": " + (Integer) hm.get(word));
}
}
}
}
}
What do I need to add to make it alphabetize/reorganize the HashMap?
An HashMap is, by default, unsorted. This because its implementation can't rely on order of elements.
If you need a sorted map then you will have to look into a TreeMap which supplies the same interface as a HashMap but it's inherently sorted on keys according to their natural ordering (or a custom Comparator). Mind that a TreeMap doesn't allow ordering on values, so if you need to sort your data by value then you will have to build your own sorted collection.
This is usually done by taking the Map.Entry<K,V> entrySet() and then build a new SortedSet by following your ordering rules.
Most maps, including HashMap, make no promises about order of contents. Consider SortedMap, or maintaining both a hash map and a sorted list in parallel.
Difference between HashMap, LinkedHashMap and TreeMap
Related
This question already has answers here:
Finding the smallest and second smallest value in an array Java
(3 answers)
Closed 8 years ago.
For my programming class I need to write a method where the code prints the fastest and the second fastest runner.
This is what I've got:
import java.util.Arrays;
class Marathon {
public static void main (String[] arguments){ `
`String[] names ={
"Alex", "Clair", "Sarah", "Andy", "Anna", "Bob"
};
int[] times ={
341, 273, 278, 329, 445, 402,
};
for (int i = 0; i < names.length; i++) {
System.out.println(names[i]+ ": " + times[i]);
}
}
}
How do I get it to show only the fastest person (lowest number) and the second fastest person (second lowest number).
Here's one way to find the fastest runner
import java.util.Collections;
import java.util.HashMap;
import java.util.Map.Entry;
class Marathon {
public static void main (String[] arguments){
HashMap<String, Integer>namez = new HashMap<String, Integer>();
namez.put("Alex", 341 );
namez.put("Clair",273 );
namez.put("Sarah",278);
namez.put("Andy",329);
namez.put("Anna",445 );
namez.put("Bob",402);
Integer min = Collections.min(namez.values());
namez.containsValue(min);
for (Entry<String, Integer>entry: namez.entrySet()){
if(entry.getValue()==min){
System.out.println(entry.getKey()+": "+entry.getValue());
String key = entry.getKey();
}
}
}
}
EDIT: Here is actually the way that finds fastest and the second fastest person from your list. It only outputs their names, which are Clair and Sarah. I hope it helps.
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
class Marathon {
public static void main (String[] arguments){
HashMap<Integer, String>namez = new HashMap<Integer, String>();
namez.put(341,"Alex");
namez.put(273,"Clair");
namez.put(278, "Sarah");
namez.put(329,"Andy");
namez.put(445,"Anna");
namez.put(402, "Bob");
ArrayList<Integer> timez = new ArrayList<Integer>();
timez.add(341);
timez.add(273);
timez.add(278);
timez.add(329);
timez.add(445);
timez.add(402);
Collections.sort(timez);
System.out.println(namez.get(timez.get(0)));
System.out.println(namez.get(timez.get(1)));
}
}
This is probably the most compact way to do it:
import java.util.*;
public class Main {
public static void main(String[] args) {
//Create the mapping:
TreeMap<Integer, String> timeToNameMapping = new TreeMap<Integer,String>();
timeToNameMapping.put(341, "Alex");
timeToNameMapping.put(273, "Clair");
timeToNameMapping.put(278, "Sarah");
timeToNameMapping.put(329, "Andy");
timeToNameMapping.put(445, "Anna");
timeToNameMapping.put(402, "Bob");
//Get the keys from the above mapping.
//Since it is a TreeMap, the keys are sorted
List<Integer> times = new ArrayList<>(timeToNameMapping.keySet());
//Print the result
System.out.println("First: " + timeToNameMapping.get(times.get(0)));
System.out.println("Second: " + timeToNameMapping.get(times.get(1)));
}
}
Output:
First: Clair
Second: Sarah
Explanation:
I am using the reverse mapping, as this enables you to just sort all the keys, and then map the first two elements of the sorted list to the names in the TreeMap (given a runtime the TreeMap above will tell you the name of the runner for that time). TreeMaps are already ordered, but since they keys in the Map are in a TreeSet we cannot use index on it to get the two first elements. That is why I convert the keySet() to an ArrayList (which allows for indexing).
To elaborate on dictionaries (Maps):
Generally when using Lists you use the get() method to get a specific element. For Lists like ArrayList and LinkedList the get() method takes an integer (an index value) and returns the element that are at that position in the list.
Maps are a bit different: Maps make a correlation between a key and a value. In the above example if I give the map the key 341, then it will give me the value "Alex". The get() method on a Map therefore takes a key of type K (in this case an Integer, but it can be any kind of object actually) and returns a value of type V (in this case a String, but can also be any object). The type of the key and value are determined when creating the Map (in this case K, V = Integer, String). The concept of telling the map exactly what types are being used are called generics.
You want to sort the array first and then print out the first two in the array. Because it is for your class I wont give you the code that you need but I gave you the perfect hint all you have to do is google how to sort the array and call on first two. Google Keyswords "Java Sort Array"
I am trying to build a many to one key value pair in java. Till now all I have manged is this
public class KeyStore {
int i=1;
Map<Integer,String> map1=new HashMap<Integer,String>();
Map<String,List<Integer>> map2=new HashMap<String,List<Integer>>();
public synchronized int put(String blobString) {
if(map1.containsValue(blobString)){
int r=blobString.hashCode()+i*blobString.hashCode();
i++;
map1.put(r, blobString);
List<Integer> j=map2.get(blobString);
List<Integer> k=j;
map2.remove(blobString);
k.add(r);
map2.put(blobString, k);
return r;
}
else{
map1.put(blobString.hashCode(),blobString);
List<Integer> x=new ArrayList<Integer>();
x.add(blobString.hashCode());
map2.put(blobString,x);
return blobString.hashCode();
}
}
public synchronized String get(int objectId) {
return map1.get(objectId);
}
What this does is if i put
ks.put("abc")
ks.put("abc")
Here ks is an instant of the class containing the above methods.
it results in
{1916062554=abc, 958031277=abc}
But what I want is
191602554,958031277=abc
and if i use get() on either of these keys it should output the value abc. Also delete() should delete the most recent key and not harm the other keys.
I thought of using
Map<ArrayList<Integer>,String> keystore=new HashMap<ArrayListInteger>,String>();
but I dont know how to implement the put method i.e how to insert a key in a map of lists. Need help with this.
EDIT 1
I am able to make the get and put methods work. Struggling with the delete method. Wrote it some what like this
Map<Integer,String> map1=new HashMap<Integer,String>();
Map<String,List<Integer>> map2=new HashMap<String,List<Integer>>();
public synchronized void delete(int objectId) {
map1.remove(objectId);
Iterator<Entry<String, List<Integer>>> it = map2.entrySet().iterator();
loop1: while (it.hasNext()) {
#SuppressWarnings("rawtypes")
Map.Entry pairs = (Map.Entry)it.next();
#SuppressWarnings("unchecked")
List<Integer> z=(List<Integer>) pairs.getValue();
if(z.contains(objectId)){
//System.out.println(z.size());
String key=(String) pairs.getKey();
System.out.println(z+" "+key);
if(z.size()==1){
map2.remove(key);
break loop1;
}
else{
z.remove(objectId);
map2.remove(key);
map2.put(key, z);
break loop1;
}
}
}
}
Basically map1 contains the mappings
123=>abc,456=>abc
and map2 contains
abc=>[123,456]
I am getting an arrayindexoutofbound exception. What I am trying in the delete method is to iterate across each blob String and then check in the list of values associated with the blobstring whetehr the required objectID is present. if it is then I remove that object id from the list and append the new mapping. Any help?
EDIT 2
The updated and working get and put methods are given above.
The Map JavaDoc says:
A map cannot contain duplicate keys; each key can map to at most one value.
But you can get around this by making the value a list of strings:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
<P>{#code java MultiValueHashMap}</P>
**/
public class MultiValueHashMap {
public static final void main(String[] ignored) {
Map<Integer,List<String>> mapOfIntStrs = new HashMap<Integer,List<String>>();
//Add elements
addStringToMap(mapOfIntStrs, 1, "one");
addStringToMap(mapOfIntStrs, 1, "two");
addStringToMap(mapOfIntStrs, 1, "three");
addStringToMap(mapOfIntStrs, 2, "four");
addStringToMap(mapOfIntStrs, 2, "five");
//Output
Set<Integer> keyNumSet = mapOfIntStrs.keySet();
Iterator<Integer> keyNumItr = keyNumSet.iterator();
while(keyNumItr.hasNext()) {
Integer keyNum = keyNumItr.next();
List<String> strList = mapOfIntStrs.get(keyNum);
System.out.println(keyNum);
for(String s : strList) {
System.out.println(" " + s);
}
}
}
private static final void addStringToMap(Map<Integer,List<String>> mapTo_addTo, int keyNum, String value) {
if(mapTo_addTo.containsKey(keyNum)) {
mapTo_addTo.get(keyNum).add(value);
} else {
List<String> strList = new ArrayList<String>();
strList.add(value);
mapTo_addTo.put(keyNum, strList);
}
}
}
Output:
[C:\java_code\]java MultiValueHashMap
1
one
two
three
2
four
five
Regarding multiple keys per value, you could certainly do this, although I'm not sure it's recommended. According to the HashMap API:
The HashMap class is roughly equivalent to Hashtable, except that it is unsynchronized and permits nulls.
And the Hashtable API:
To successfully store and retrieve objects from a hashtable, the objects used as keys must implement the hashCode method and the equals method.
So while this would work with ArrayList<Integer> keys, for anything with customized keys, containing non-standard classes, unless you are correctly implementing hashCode() for those objects, the HashMap may not function properly.
It seems like you need a couple of data structures as fields in your class:
stringMap: Map<Integer,String>
{1916062554=abc, 958031277=abc}, etc.
because for get you want to look up items by key
keys: Map<String,List<Integer>>
{ "abc" = {1916062554, 958031277}
because for delete you want to know the keys for a given item, in order.
To add to the Map:
public void put(String item) {
List<Integer> list = getOrCreateList(item,keys);
int key = calculateKey(item,list);
list.add(key);
stringMap.put(key,item);
}
private static List<Integer> getOrCreateList(String item, Map<String,List<Integer>> map) {
List<Integer> list = map.get(item);
if(list == null) {
list = new ArrayList<Integer>();
map.put(item,list);
}
return list;
}
To get from the map is easy:
public String get(int key) {
return stringMap.get(key);
}
To delete from the map -- if I understand your requirements correctly -- you need to find the most recent key in the list corresponding to the key provided...
public void delete(int key) {
String item = stringMap.get(key);
if(item == null) {
// ... deal with
}
List<Integer> keys = keys.get(item);
// lazily using methods which don't exist in the Java API
// but which illustrate the point.
keys.removeLast();
if(keys.isEmpty()) {
stringMap.remove(key);
list.remove(item);
}
}
I have been working with Maps at present and I am baffled by how I can get my program to work effectively. I can iterate over the map get the keys and values and sort them in alphabetical and reverse alphbetical order quite easily and have used custom comparators for this. However, I am now trying to sort the map based on the key with the most values. The values are a list of objects I have created and can be thought of as this scenario.
There is an Atlas(like a catalog) that has lots of towns (the key of type string). That contains Shops(List). I want to sort this so that the town with the most shops is displayed first and goes in descending order with the secondary sorting being based on town alphabetically and return a string representing this.
I have used the Comparator interface with seperate classes for each one alphabetically and reverse alphabetically so far and wish to follow the same pattern for learning purposes However this has me completely stumped.
Example:
class Atlas {
Map<String, List<Shop> atlas = new HashMap<String, List<Shop>();
void addShop(Shop shop){
//if(Atlas already contains){
get the town and add the shop to it.
}
else{
add the town as the key and the shop as the value in the list
}
}
List<Shop> getAllShopsFromTheGivenTown(String givenTown){
//if(Atlas contains givenTown){
return the givenTown from the List.
}
else{
//Return an ArrayList emptyList
}
}
public String returnAllTownsAndShopsAlphbetically(){
String tmpString = "";
List<String> keys = new LinkedList<String>(atlas.keySet());
TownComparatorAtoZ tc = new TownComparatorAtoZ();
Collections.sort(keys, tc);
for(String town : keys){
List<Shop> shops = new LinkedList<Dealer>(atlas.get(town));
ShopComparatorAtoZ sc = new ShopComparatorAtoZ();
Collections.sort(shop, sc);
for(Shop shop : shops){
if(tmpString.isEmpty()){
tmpString = tmpString + town + ": " + shop.getName();
}
else if(tmpString.contains(town)){
tmpString = tmpString + ", " + shop.getName();
}
else{
tmpString = tmpString + " | " + town + ": " + shop.getName(); }
}
}
return tmpString;
}
}
As can be seen from above (although not the cleanest and most efficient) returns things alphabetically and will be reformatted into a string builder. However, I am wondering how I can use a comparator to achieve what I am after and if someone could provide a code snippet with an explanation of what it actually does I would be grateful as its more about understanding how to do it not just getting a copy and pasted lump of code but need to see if visually in code to understand it.
SO output I want to be something like
manchester: m&s, h&m, schuch | birmingham: game, body shop | liverpool: sports
You can try something like this:
public static Map<String, List<Shop>> mySortedMap(final Map<String, List<Shop>> orig)
{
final Comparator<String> c = new Comparator<String>()
{
#Override
public int compare(final String o1, final String o2)
{
// Compare the size of the lists. If they are the same, compare
// the keys themsevles.
final int sizeCompare = orig.get(o1).size() - orig.get(o2).size();
return sizeCompare != 0 ? sizeCompare : o1.compareTo(o2);
}
}
final Map<String, List<Shop>> ret = new TreeMap<String, List<Shop>>(c);
ret.putAll(orig);
return ret;
}
Explanation: TreeMap is the basic implementation of a SortedMap, and it can take a comparator of key values as an argument (if no comparator is passed as an argument, natural ordering of the keys prevails). Here we create an ad hoc comparator comparing the list sizes of the original map passed as an argument, and if the sizes are equal, it compares the keys themselves. Finally, we inject all elements from the origin map into it, and return it.
What if you try something like the following:
private static final Comparator<Map.Entry<String, List<Shop>>> CountThenAtoZ =
new Comparator<Map.Entry<String, List<Shop>>>() {
#Override
public int compare(Map.Entry<String, List<Shop>> x, Map.Entry<String, List<Shop>> y) {
// Compare shop count first. If equal, compare keys alphabetically.
int cmp = ((Integer)x.getValue().size()).compareTo(y.getValue().size());
return cmp != 0 ? cmp : x.getKey().compareTo(y.getKey());
}
};
...
public String returnAllTownsAndShopsAlphbetically() {
List<Map.Entry<String, List<Shop>>> entries = new ArrayList<>(atlas.entrySet());
Collections.sort(entries, CountThenAtoZ);
String result = "";
boolean firstTown = true;
for (Map.Entry<String, List<Shop>> entry : entries) {
if (!firstTown) result += " | "; else firstTown = false;
result += entry.getKey() + ": ";
boolean firstShop = true;
TreeSet<Shop> sortedShops = new TreeSet<>(new ShopComparatorAtoZ());
sortedShops.addAll(entry.getValue());
for (Shop shop : sortedShops) {
if (!firstShop) result += ", "; else firstShop = false;
result += shop.getName();
}
}
return result;
}
The way this works is to first create a list of the atlas entries in exactly the order we want. We need access to both the keys and their associated values to build the correct ordering, so sorting a List of Map.Entry instances is the most convenient.
We then walk the sorted list to build the resulting String, making sure to sort the shops alphabetically before adding them to the String.
I have the following code which adds some arrays to a hashmap but then I want access those arrays to do some work on them later. I've gotten this far but can't figure the rest out to make it work....
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
public static void main(String[] args) {
String[][] layer1 = {
{"to1", "TYPE1", "start"},
{"to2", "TYPE1", "start"}
};
String[][] layer2 = {
{"to3", "TYPE2" ,"item1"},
{"to3", "TYPE2" ,"item2"}
};
HashMap<String,Object> hashMap = new HashMap<String,Object>();
hashMap.put("layer1", layer1);
hashMap.put("layer2", layer2);
Iterator<Entry<String, Object>> iterator = hashMap.entrySet().iterator();
while(iterator.hasNext()){
hashMap.values().toArray();
for (???) {
// lets print array here for example
}
}
}
Smells like homework, but a few suggestions -
there's no reason for your Hashmap to be of the form <String,Object> - make it <String, String[][]> , as that's what you're storing.
You're iterating twice. You either
- iterate through the map, either the keys, values or entries. Each item is an iterator return value, e.g.
for (String[][] s:map.values()){
...
}
hashmap.values.toArray gives you all of the contents, which is the same thing your iterator is doing.
if you're only iterating through the contents, then you're not really using a map, as you're never making use of the fact that your values are available by key.
... just mixing too many languages to learn atm
Can I suggest that you need to stop and take the time to learn Java properly. Your code looks like you are trying to write "perlish" ... associative arrays and arrays instead of proper types. The end result is Java code that is slow and fragile compared with code that is designed and written using the Java mindset.
It might seem like you are being productive, but what you are producing is likely to be problematic going forward.
Your while loop should look like -
while(iterator.hasNext()){
String[][] arr = (String[][])iterator.next().getValue();
for (String[] strings : arr) {
for (String string : strings) {
System.out.println(string);
}
}
}
Your code is bad formed here:
while(iterator.hasNext()){
hashMap.values().toArray();
for (???) {
// lets print array here for example
}
}
You try to iterate using the Iterator "iterator" but next you call to
hashMap.values().toArray();
To get the next item of the loop you need to use iterator.next(); to fetch it. Also is good to change the "Object" by String[][] or to List<String[]> or List<List<String>>.
import java.util.HashMap;
import java.util.Map;
import java.util.Iterator;
import java.util.Map.Entry;
public static void main(String[] args) {
String[][] layer1 = {
{"to1", "TYPE1", "start"},
{"to2", "TYPE1", "start"}
};
Map<String,String[][]> map= new HashMap<String,String[][]>();
map.put("layer1", layer1);
Iterator<Entry<String, String[][]>> iterator = map.entrySet().iterator();
while(iterator.hasNext()){
Entry<String, String[][]> entry = iterator.next();
System.out.println("Key:" + entry.getKey());
String[][] value = entry.getValue();
for(int x=0;x<value.length;x++){
for(int y=0;y<value[x].length;y++){
System.out.println("String[" + x + "][" + y + "]:" + value[x][y]);
}
}
}
}
Also you can use "for each" loop to simplify the code insted using the "while":
for (Entry<String, String[][]> entry : map.entrySet()){
System.out.println("Key:" + entry.getKey());
String[][] value = entry.getValue();
for(int x=0;x<value.length;x++){
for(int y=0;y<value[x].length;y++){
System.out.println("String[" + x + "][" + y + "]:" + value[x][y]);
}
}
}
Or if you only need the values:
for (Entry<String, String[][]> entry : map.values()){
String[][] value = entry.getValue();
for(int x=0;x<value.length;x++){
for(int y=0;y<value[x].length;y++){
System.out.println("String[" + x + "][" + y + "]:" + value[x][y]);
}
}
}
I am piping in a file. I am tracking word pairs from the file. Using a treemap the keys are all sorted. However, when i add words to those keys they are not sorted.
here is the part i need help on in the process function:
private static void process(){
if(!result.containsKey(thisWord)){
result.put(thisWord, new ArrayList<String>());
}
// Add nextWord to the list of adjacent words to thisWord:
result.get(thisWord).add(nextWord); // nextword is not sorted within the key
thisword is sorted
nextWord is not..
Can i use Collections.sort(result); somehow?
im just not sure how i get to the nextWord within the result to do that.
or, is there no way to do it within my situation. I would rather not change things unless you recommend it.
This is the program
import java.util.Map.Entry;
import java.util.TreeSet;
import java.io.*;
import java.util.*;
public class program1 {
private static List<String> inputWords = new ArrayList<String>();
private static Map<String, List<String>> result = new TreeMap<String, List<String>>();
public static void main(String[] args) {
collectInput();
process();
generateOutput();
}
private static void collectInput(){
Scanner sc = new Scanner(System.in);
String word;
while (sc.hasNext()) { // is there another word?
word = sc.next(); // get next word
if (word.equals("---"))
{
break;
}
inputWords.add(word);
}
}
private static void process(){
// Iterate through every word in our input list
for(int i = 0; i < inputWords.size() - 1; i++){
// Create references to this word and next word:
String thisWord = inputWords.get(i);
String nextWord = inputWords.get(i+1);
// If this word is not in the result Map yet,
// then add it and create a new empy list for it.
if(!result.containsKey(thisWord)){
result.put(thisWord, new ArrayList<String>());
}
// Add nextWord to the list of adjacent words to thisWord:
result.get(thisWord).add(nextWord); // need to sort nextword
// Collections.sort(result);
}
}
private static void generateOutput()
{
for(Entry e : result.entrySet()){
System.out.println(e.getKey() + ":");
// Count the number of unique instances in the list:
Map<String, Integer> count = new HashMap<String, Integer>();
List<String> words = (List)e.getValue();
for(String s : words){
if(!count.containsKey(s)){
count.put(s, 1);
}
else{
count.put(s, count.get(s) + 1);
}
}
// Print the occurances of following symbols:
for(Entry f : count.entrySet()){
System.out.println(" " + f.getKey() + ", " + f.getValue() );
}
}
System.out.println();
}
}
If you want the collection of "nextword"s sorted, why not use a TreeSet rather than an ArrayList? The only reason I can see against it is if you might have duplicates. If duplicates are allowed, then yes, use Collections.sort on the ArrayList when you're done adding to them. Or look in the Apache Commons or Google collection classes - I don't know them off the top of my head, but I'm sure there is a sorted List that allows duplicates in one or both of them.
result.get(thisWord).add(nextWord);
Collections.sort(result.get(thisWord));
Y Don't you try some thing like this
Collections.sort(inputWords);