Java Hashmap: Get key from a given ARRAY of values - java

I have a hashMap called prizeWinners. The key for each pair in the hashMap is the year a nobel prize was won. The value is the name(s) of the winners. The value is an array of Strings, because in any given prize year, there can be up to 3 winners. My question is this: Given the name of a winner, return the year in which they won the prize. Interestingly enough, the return value also needs to be a string: public String getYearWon(String name), where name is the name of the winner.
public class NobelPrizeWinners
{
private HashMap<Integer, String[]> prizeWinners;
public NobelPrizeWinners
{
prizeWinners = new HashMap<Interger, String[]>();
prizeWinners.put(2009, new String[] {"Barack H. Obama"});
prizeWinners.put(2008, new String[] {"Martti Ahtisaari"};
prizeWinners.put(2007, new String[] {"IAEA", "Mohamed ElBaradei"});
//and many more
}
public String getYearWon(String name)
{
//code here
}
}
And this is where I get stuck: I cannot seem to access the array correctly to iterate through it and get the key. There are several methods in my assignment requiring me to do so (for example, to print out the names of all winners), but I only get the hashmap address, not the contents of the array itself.

Iterate through the prizeWinner keys (years). For each year, get the winners String array and convert it to a list, then call the contains method to see if the winners list contains the winner name passed as parameter. If it's the case, we stop looping and return the year as a String. If we went through all the years but didn't find the winner's name, we would return null
private HashMap<Integer, String[]> prizeWinners;
public PartsPortlet()
{
prizeWinners = new HashMap<Integer, String[]>();
prizeWinners.put(2009, new String[]{"Barack H. Obama"});
prizeWinners.put(2008, new String[]{"Martti Ahtisaari"};
prizeWinners.put(2007, new String[]{"IAEA", "Mohamed ElBaradei"});
//and many more
}
public String getYearWon(String name) {
for (int year : prizeWinners.keySet()) {
if (Arrays.asList(prizeWinners.get(year)).contains(name)) {
return String.valueOf(year);
}
}
return null;
}

Related

How can I get a HashMap value depending on the key? [duplicate]

This question already has answers here:
Why do I need to override the equals and hashCode methods in Java?
(31 answers)
Closed 2 years ago.
So I have an ArrayList with objects that have name, id, salary etc. And a Queues with another ArrayList objects, model, year etc.
I created a HashMap and used the ArrayList objects as keys and the queues as values, associating each queue for a object in the arraylist.
The thing is, I have to list all the values for a determined key.
I would like to know how can I return all the values of a hashmap depending on the name value of the object.
For example this my map:
{Mech [Name = Ella McCarthy , ID = 1]=[Car [model=Civic, year=2010, fix=flat tyres], Car [model=Audi A3, year=2012, fix=something broken]],
Mech [Name = Josh Reys , ID = 1]=[Car [model=Cruze, year=2014, fix=something broken], Car [model=Impala, year=1990, fix=something broken]]}
Is there any way of returning the value if the name in the object in the key equals to Ella McCarthy?
Next code may comprehensive for you:
public class MapExample {
private static final String DETERMINED_KEY = "Ella McCarthy";
Queue<Car> queue = new PriorityQueue<>();
Map<Mech, Queue<Car>> map = new HashMap<>();
Queue<Car> getValuesByNameInKeyObjectWithStreams() {
Queue<Car> cars = map.entrySet()
.stream()
.filter(mapEntry -> mapEntry.getKey().getName().contentEquals(DETERMINED_KEY))
.map(Map.Entry::getValue)
.findFirst()
.orElseThrow(); // Throw exception if did't find according value. Or return another result with orElse(result)
return cars;
}
Queue<Car> getValuesByNameInKeyObjectBeforeJava8() {
for (Map.Entry<Mech, Queue<Car>> entry : map.entrySet()) {
String mechName = entry.getKey().getName();
if (mechName.equals(DETERMINED_KEY)) {
return entry.getValue();
}
}
// Throw exception or return another result
throw new RuntimeException("If didn't find exception");
}
}
class Mech {
String name;
public String getName() {
return name;
}
}
class Car {
String value;
}
If you prefer functional style and use java 8 or higher, peek getValuesByNameInKeyObjectWithStreams method.

Check whether the array contains more than 1 equivalent value

I have an array where i get the values as names of some students and the array is dynamically populates and it does not contain static values. Now what i want to check is that whether the array obtained has any same name. Here is some part of my code,
ArrayList<Student> rows;
for (Student name: rows) {
}
I dont know how to check. I have used compartor but it didnt work. Can anyone help. Inside the array I will get all student names
Use a list to store any duplicate names:
List<String> dups = new ArrayList<>();
and a set where you will store names:
Set<String> names = new HashSet<>();
A set contains only unique values.
Now iterate through your list
(I guess your Student class has a method like getName() to obtain the student's name):
for (Student student : rows) {
String studentname = student.getName();
if (!names.add(studentname) {
dups.add(studentname);
}
}
The method names.add() returns false when it's not possible for an item to be added to the set because it already exists in it.
So when it returns false it encountered a duplicate name and the name is added to the dups list.
When this loop finishes, you can find all the duplicate student names in the dups list and show them in a toast:
if (dups.size() > 0) {
StringBuilder sb = new StringBuilder("There are duplicates: ");
for (String studentname : dups) {
sb.append(studentname).append(", ");
}
String msg = sb.toString();
msg = msg.substring(0, msg.length() - 2);
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
A way to check it is to convert your list to a set and check if the size got reduced (because Sets do not accept duplicate values), something like :
ArrayList<Student> rows;
Set<Student> set = new HashSet<Student>(rows);
if(set.size() < rows.size()){
// In this case you have repeated values in the list
}
Note that it depends on your equals method of the Student class to determine how Students are compared, so since you are checking againist their names you might have this equals method inside your Student class:
#Override
public boolean equals(Object obj) {
if( obj instanceof Student) {
return (obj.name.equals(name));
}
return false;
}
Store the data in HashMap with key as studentName and value as student object
Map studentMap = new HashMap<>()
If you add the data with same key again , the data gets updated
studentMap.put(studentName, Student)
To check if key exists and update accordingly
if(studentMap.containsKey(studentName)){
// logic if key already exists
}else{
//logic if key doesn't exists
}
If you want list instead of map , then get list from map
List studentList = new ArrayList(studentMap.values())
Check this sample java class used to count no of duplicate elements.
public class CountDuplicate {
public static void main(String[] args) {
ArrayList<String> arrayList = new ArrayList<String>();
arrayList.add("aaa");
arrayList.add("bbb");
arrayList.add("aaa");
arrayList.add("bbb");
arrayList.add("ccc");
arrayList.add("bbb");
arrayList.add("ccc");
arrayList.add("aaa");
arrayList.add("ccc");
arrayList.add("bbb");
HashSet<String> hsUnique = new HashSet<String>(arrayList);
for (String str : hsUnique) {
System.out.println(Collections.frequency(arrayList, str) +" times "+ str);
}
}
}

Comparator is removing duplicate objects from treemap

I'm working on a highscore system that reads from a file line-by-line and adds all lines into a treemap, sorts the treemap and adds the scores and names into a new file, highest score being at the top.
I've gotten the system close but for some unknown reason the code is removing duplicate entries, for example, i have 3 scores.
1 : Sander
1 : Sander
2 : Mark
Printing my treemap would look like this:
I would like the code to show Sander twice.
I've been stuck for quite some time and would appriciate some help, here is my code:
public void sortScores() throws IOException {
File input = new File("scores.txt");
File output = new File("outputscores.txt");
FileInputStream fis = new FileInputStream(input);
FileOutputStream fos = new FileOutputStream(output);
BufferedReader in = new BufferedReader(new InputStreamReader(fis));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(fos));
String aLine;
while ((aLine = in.readLine()) != null) {
String[] scoreAndName = aLine.split(" : ");
int score1 = Integer.parseInt(scoreAndName[0]);
String name1 = scoreAndName[1];
unsortMap1.put(score1, name1);
}
Map<Integer, String> treeMap = new TreeMap<Integer, String>(
new Comparator<Integer>() {
#Override
public int compare(Integer o1, Integer o2) {
if (o1 >= o2) {
return -1;
} else {
return 1;
}
}
});
treeMap.putAll(unsortMap1);
System.out.println(treeMap);
}
That's exactly the way Map is supposed to work. From documentation:
An object that maps keys to values. A map cannot contain duplicate keys; each key can map to at most one value.
put(key, value) replace the old value with the new one.
While you can make it work using Map<Integer, List<String>> (for example), that's cumbersome and doesn't look clean. List is a better data structure for this task.
I would define a class Score, use it to populate the list, and sort it with a custom comparator. You could also make Score implement Comparable instead of using a Comparator.
Here's an example that uses Comparator.comparingInt().
List<Score> scores = new ArrayList<>();
scores.add(new Score(1, "Name")); //adding an element
scores.sort(Comparator.comparingInt(Score::getScore)); //sorting
class Score {
private final int score;
private final String name;
Score(int score, String name) {
this.score = score;
this.name = name;
}
public int getScore() {
return score;
}
public String getName() {
return name;
}
}
You have chosen the wrong collection type.
A Map<Integer, String> will store only one String value for any possible Integer. So given a score (e.g. 1) it can store a single name. Not the same name multiple times.
It appears that you are trying to sort records representing scores. To do that, you are going to need to create a custom class whose instances represent the records.
You can sort the records a number of ways:
Put them into an array use Arrays.sort
Put them into a list and use Collections.sort
Implement your own sort algorithm. (Not recommended. It is better not to waste your time "reinventing the wheel".)
You will either need to implement a Comparator to order the records1, or make your record class implement Comparable.
For more details, please read the respective javadocs.
But you cannot use a TreeMap or TreeSet (or any other Map or Set implementations) for this. Your records are not unique, and those data structures will remove duplicates2.
1 - From Java 8, the Comparator interface has some static helper methods for creating comparators; e.g. Comparator.comparingInt().
2 - Not strictly true. You could do this if your records had a 3rd field containing a unique identifier which you used as a tie-breaker in the comparator. Or you could use a Map<YouRecord, Integer>, where the integer represents a count of records that are "equal".

In Java: What happens if I change a key in an HashMap to be equal to another key? [duplicate]

This question already has answers here:
Changing an object which is used as a Map key
(5 answers)
Closed 5 years ago.
I know that I can not have 2 keys in a HashMap which are equal (by the equals()-method). And if I try to add a key-value-pair to the HashMap with the key already existing, the old value is just replaced by the new one.
But what if I change an already existing key to be equal to another existing key?
How will the map.get() method behave in this case (applied to one of these equal keys)?
Very simple example below.
public class Person{
private int age;
private String name;
public Person(int a, String n){
age = a;
name = n;
}
public void setAge(int a){ age = a; }
public int getAge(){return age; }
public String getName() {return name; }
#Override
public boolean equals(Object o){
if(!(o instanceof Person)){return false;}
Person p = (Person) o;
return ((p.getName().equals(this.getName())) && (p.getAge() == this.getAge()));
}
#Override
public int hashCode(){return age;}
}
public class MainClass{
public static void main(String[]args){
Person p1 = new Person("Bill", 20);
Person p2 = new Person("Bill", 21);
HashMap<Person, String> map = new HashMap<>();
map.put(p1, "some value");
map.put(p2, "another value");
p1.setAge(21);
String x = map.get(p1); // <-- What will this be??
System.out.println(x);
}
}
When you mutate a key which is already present in the HashMap you break the HashMap. You are not supposed to mutate keys present in the HashMap. If you must mutate such keys, you should remove them from the HashMap before the change, and put them again in the HashMap after the change.
map.get(p1) will search for the key p1 according to its new hashCode, which is equal to the hash code of p2. Therefore it will search in the bucket that contains p2, and return the corresponding value - "another value" (unless both keys happen to be mapped to the same bucket, in which case either value can be returned, depending on which key would be tested first for equality).
In short: p1 will not be reachable anymore.
In general the map is using the hash function to split the keys to buckets and then the equal function to locate the correct key-value. when you change the value of p1 and with that its hash value. If you will look for it the map will look for the value in a different bucket and will not see it and the p1 that is in the map will not be reachable.

How to use a Comparator recursively?

I have to rank the teams in the array "names" (below) in order of who won the most games. If two teams won the same amount of games then I have to compare the wins of the teams that beat them. The code I have so far is below.
The full problem statement is given here: http://www.cs.duke.edu/csed/newapt/tournamentrank.html
So I want to use the comparator recursively. How can the Comparator can have access to the original data? I tried creating a Team class that takes a variable of the same class for the team that beat it, but that clearly doesn't work. Stuck here, please help!
public class TournamentRanker implements Comparator<String>{
public class Team {
String name;
Integer wins;
Team beatEm;
}
//HOW TO make maps visible to comparator?
public String[] rankTeams(String[] names, String[] lostTo) {
//map all teams to number of wins & to team that beat them
ArrayList<String> teams = new ArrayList<String>();
HashMap<String, Integer> Teamwins = new HashMap<String, Integer>();
HashMap<String, String> Whobeat = new HashMap<String, String>();
for(int x=0; x<names.length; x++)
{
if(!teams.contains(names[x]))
teams.add(names[x]);
if(!Teamwins.containsKey(names[x]))
Teamwins.put(names[x], 0);
Whobeat.put(names[x], lostTo[x]);
if(!Teamwins.containsKey(lostTo[x]) && !lostTo[x].equals(""))
Teamwins.put(lostTo[x], 0);
if(!lostTo[x].equals(""))
Teamwins.put(lostTo[x], (Teamwins.get(lostTo[x])+1));
}
for(String s: names)
{
Integer wins = Teamwins.get(s);
Team beatEm = new Team(Whobeat.get(s), Teamwins.get(Whobeat.get(s)), ????)
}
//SORT list & turn into ARRAY
Comparator<String> comp = new TournamentRanker();
Collections.sort(teams, comp);
String [] sortedTeams = new String[teams.size()];
return teams.toArray(sortedTeams);
}
//NEED to use compareTo***?? OTHER strategy????
//USE COMPARTOR - how to access all the data?
public int compare(String team1, String team2){
}
}
To make the maps visible, I suggest making the Comparator an inner class of TournamentRanker, and making the maps instance members of the TournamentRanker class, as follows:
public class TournamentRanker {
public class Team {
String name;
Integer wins;
Team beatEm;
}
// Map all teams to number of wins & to team that beat them
ArrayList<String> teams = new ArrayList<String>();
HashMap<String, Integer> Teamwins = new HashMap<String, Integer>();
HashMap<String, String> Whobeat = new HashMap<String, String>();
public String[] rankTeams(String[] names, String[] lostTo) {
TeamComparator teamComparator = new TeamComparator();
// Use teamComparator to sort teams.
...
}
private TeamComparator implements Comparator<String> {
public int compare(String team1, String team2){
// This function can now access the maps.
// Perform the comparison here.
...
}
}
}
If your goal is to write an object-oriented program, I would structure it as follows:
A Game class containing references to the two teams that played the game, and each team's score.
A Team class containing a Map of games played (Game objects) indexed by opposing team ID. If two teams can meet more than once than you'll need a "multi-map" that allows more than one value object per key.
A Tournament object containing both the Team instances (probably a Map indexed by team name) and Game objects (another Map indexed by some unique key of your choosing).
In your comparator, you can compare two teams' win-loss record, and in case of ties look at each team's individual games.

Categories

Resources