Key with multiple values to be accessed in two ways JAVA - java

I'm reading different keys and their corresponding keys from a textfile.
I want to create a hashmap that takes in the keys and their corresponding keys. It needs to be accesible in both ways.
How do I do this?
I've managed to do it but it works only for the left side.

As every country has only a few members I would do it with a map and just implement a method to update the state of each country in a pair of neighbours. If it was, however, a dense structure, i.e. every element had nearly all other as neighbours, I would recommend using an indicator matrix: rows and columns are countries and a true value on the intersection defines they are neighbours. But here goes the first solution, with a map:
public class Countries
{
private final Map<String, Set<String>> countries = new HashMap<String, Set<String>>();
public void addCountry(#NotNull String name) {
addNeighbourPair(name, null);
}
public void addNeighbourPair(#NotNull String first, String second) {
if (!hasCountry(first)) {
countries.put(first, new HashSet<String>());
}
if (second != null) {
if (!hasCountry(second)) {
countries.put(second, new HashSet<String>());
}
countries.get(first).add(second);
countries.get(second).add(first);
}
}
public boolean hasCountry(String name) {
return countries.containsKey(name);
}
public Set<String> getNeighbours(String name) {
return countries.get(name);
}
/*
* the correctness of this loader is validated only with respect
* to using the Countries class :)
*/
public static Countries fromFile(String borders) {
Countries countries = new Countries();
Scanner bordersload = new Scanner(new File(borders));
while (bordersload.hasNextLine()) {
String line = bordersload.nextLine();
String[] values=line.split(" : |:|: | :");
String key=String.valueOf(values[0]);
String key1=String.valueOf(values[1]);
countries.addNeighbourPair(key, key1);
}
bordersload.close();
return countries;
}
}
Usage:
Countries countries = Countries.fromFile("path/to/file");

Each map entry should contain a set of countries that borders it. Every country should have it's own Map entry

You can use a map of <String, Set<String>>
Where key is a country and the value is a set of neighbors. For each line, check if the country exists in the map, if it does, update its neighbor (add new neighbor in the set). If doesn't, create a new entry with value.

Related

HashMap / ArrayList wont take multiple values per key

I want to create a HashMap that has a key of type String and a value of a List of Objects that is set up in another class.
The code I have tried works in that it adds a key and a value to the map, but wont add multiple values to 1 key. I.E I would like Key x to have values 1,2 and 3 but it just seems to overwrite the last value rather than add another one.
This is my current code:
public class LeagueAdmin {
private Map<String, List<Team>> teams;
/**
* Constructor for objects of class LeagueAdmin
*
*/
public LeagueAdmin() {
this.teams = new HashMap<>();
}
public void addTeam(String division, Team team) {
if(!this.teams.containsKey(division))
{
List<Team> Team = new ArrayList<>();
Team.add(team);
this.teams.put(division, Team);
} else {
List<Team> newTeam = this.teams.get(division);
}
}
}
As I said, when I add multiple values to the key string 'top' for example I expect 'top' to show me all the values added to it, instead it only shows the latest one added. Also as mentioned the Team object is handled in a separate class file.
Your else is incomplete. You make a list but never add to it when it sees that the key division exists. Add
newTeam.add(team);
to your else statement

How do I access the values in an object inside a HashMap

I'm attempting to access values that are held inside a Class which is listed in a HashMap.
In my first class I create a HashMap which links to the "LiftingStats" class.
Map<String, LiftingStats> fitnessGoals = new HashMap<String, LiftingStats>();
In the LiftingStats class I do the following...
public class LiftingStats
{
public String activity;
public String weightType;
public int weight;
public double difficulty;
/**
* Constructor for objects of class LiftingStats
*/
public LiftingStats()
{
this.run();
}
/**
* test method to fill values
*/
public void run(){
//code
this.activity = "bench press";
this.weightType = "Kg";
this.weight = 100;
this.difficulty = 8.5;
}
I'm running a test method to fill the hashmap with some values
public void testMethod(){
fitness.put("activityone", new LiftingStats());
fitness.put("activitytwo", new LiftingStats());
There are many ways to access them.
For retrieving the value of a specific key entry
LiftingStats valueForOne = fitness.get("activityone");
For retrieving values without concern for keys
Collection<LiftingStats> values = fitness.values();
For retrieving key and value pairs
Set<Map.Entry<String, LiftingStats>> entries = fitness.entrySet();
for (Map.Entry<String, LiftingStats> entry : entries) {
entry.getValue();
}
or some variant.
A Map is a Data Structure consisting of Key, Value pairs. In this case you have two keys that reference two instances of LiftingStats objects. To access these objects simply use your specific key to retrieve the object(s). Ex:
LiftingStats current = fitness.get("activityone");
With your reference to current you can perform operations on that specific LiftingStats object.
Similarly, you can 'daisy-chain' function calls together like this and still mutate the object within the Map. Ex:
fitness.get("activityone").someMethod();
You can adapt this answer to your problem :
How to efficiently iterate over each Entry in a Map?
Map<String, LiftingStats> fitnessGoals = new HashMap<String, LiftingStats>();
for (Map.Entry<String, LiftingStats> entry : fitnessGoals.entrySet())
{
//What you need to do with your map
}
Another way by which you can access variables of an object in HashMap is by typecasting the data fetched by getValue() method of a Hashmap into the user defined class.
You can use the following code:
Map<String, LiftingStats> lstats= new HashMap<String, LiftingStats>();
for (Map.Entry ls:lstats.entrySet()) {
System.out.println(ls.getKey()+" "+((LiftingStats)ls.getValue()).activity);
}
Any variable present in the class can be accessed simply by using ((LiftingStats)ls.getValue()).Var_name . where Var_name is the name of any class variable.

How to write my own comparator class in java?

I didn't find proper solution for the below scenario. I have employee names and location. In each location many employees can work.
Example: assume that employee names are unique so I consider it as a key and value as location.
TreeMap<String,String> t=new TreeMap<String,String>();
t.put(mike, Houston);
t.put(arian, Houston);
t.put(John, Atlanta);
Well my scenario is i have to write my own comparator where location is sorted first and when there are multiple locations of same name then they need to be sorted by employees. Any kind of help is appreciated.
you need a structure, and compareTo:
public class EmpLoc implements Comparable<EmpLoc> {
String employee;
String location;
public EmpLoc (String _employee, String _location)
{
employee=_employee;
location=_location;
}
#Override
public int compareTo(EmpLoc other)
{
int last = this.location.compareTo(other.location);
return last == 0 ? this.employee.compareTo(other.employee) : last;
}
}
The problem is in your data structure. TreeMap ensure your keys are always sorted in an order, but your key doesn't have full information you need to sort. Instead what you need is probably
TreeSet<Employee> employees = new TreeSet<>(employeeComparator);
where Employee is:
public class Employee {
private String name;
private String location;
/* getters & setters omitted */
}
Now you can create a comparator for Employee
You can use similar structure:
Map<String, List<String>> map = new TreeMap<>(<your_own_comparator_for_locations_or_default_one>);
This is Multimap, and this is implementation by conventional means, but also there are third-party implementation, e.g. Guava. Guava has some sorted, synchronized and immutable implementations of multimaps, you can use them by default or to see how to do some things.
You can put values like below:
public void putEmployees(String location, String employee) {
List<String> employees = map.get(location);
if (employee == null) {
employees = new ArrayList<>();
}
employees.add(employee);
Collections.sort(employees, <your_own_comparator_for_employees_or_default_one>);
map.put(location, employees);
}

Multi Key Hashmap

Recently I had an interview to save the huge count of employee details in DS.
I gave the solution as Hashmap with emp Id as key.
The follow up question was if the user wants to search based on name how to implement it. I suggested to use emp name as key and save all the employees with same name as Arraylist.
The next follow up question was tricky, need to create ONE map where user can search based on emp Id or emp name. How to implement this in map?
Implement it in memory efficient way.
This is a dirty solution (yes--very dirty, never do it on production!), but it will work if keys are of different types and one is not subtype of another (e.g. long and String). Put every employee by both keys, and get by provided key, either id or name:
Map<?, List<Employee>> map = new HashMap<>();
public void putEmployee(Employee e) {
map.put(e.id, Arrays.asList(e)); // put by id
if (!map.containsKey(e.name)) {
map.put(e.name, new ArrayList<>());
}
map.get(e.name).add(e); // put by name
}
public Employee getById(long id) {
return map.containsKey(id) ? map.get(id).get(0) : null;
}
public List<Employee> getByName(String name) {
return map.containsKey(name) ? map.get(name) : Collections.emptyList();
}
In production code, I'd use two separate maps or custom dictionary class.
I have come up with a solution. Please post your suggestions.
Step 1: Form the hashmap with emp id as key and emp object as value.
Step 2: For the same name create a list of emp id who matches the name Ex: name = 'XYZ' id={101,102,103,...}
Step 3: Insert this name as key and arraylist as value to the same map
Here we are not storing complete employee detail twice. Just trying to maintain a relationship between name and id. So comparatively it could be memory efficient.
This is a pretty easy question to answer: Just convert the IDs to Strings and store employees twice - once under the name and again under the id-as-string.
Your idea of using a List as the value is fine - for IDs, the list would be of size 1.
Note that it would be better to use two maps, because you only ever have one employee per ID and you wouldn't have to deal with a list of size 1 as a degenerate case, so:
Map<Integer, Employee> employeesById;
Map<String, Set<Employee>> employeesByName;
Especially note that you wouldn't use less memory by using just one map. In fact, you would use more memory than storing employees in separate maps for ID keys and name keys.
One way to do this would be to create a Key object that can be searched by either the name or the id:
public enum KeyType {
ID, NAME;
}
public class SearchKey {
private KeyType keyType;
private String value;
// constructor and getters snipped for brevity's sake
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
SearchKey searchKey = (SearchKey) o;
return keyType == searchKey.keyType && value.equals(searchKey.value);
}
#Override
public int hashCode() {
int result = keyType.hashCode();
result = 31 * result + value.hashCode();
return result;
}
public class Directory {
private Map<SearchKey, Set<Employee>> directory = new HashMap<>();
public void addEmployee(Employee e) {
// Add search by id
directory.put
(new SearchKey(KeyType.ID, e.getId()), Collections.singleton(e));
// Add search by name
SearchKey searchByName = new SearchKey(KeyType.NAME, e.getName());
Set<Employee> employees = directory.get(searchByName);
if (employees == null) {
employees = new HashSet<>();
directory.put(searchByName, employees);
}
employees.add(e);
}
public Employee getById (String id) {
// Assume that the ID is unique
return directory.get(new SearchKey(KeyType.ID, id)).iterator().next();
}
public Set<Employee> getByName (String name) {
return directory.get(new SearchKey(KeyType.NAME, name));
}
}

Get key from HashMap in Android by position or index

I have:
public static HashMap<String, String> CHILD_NAME_DOB = new HashMap<>();
Suppose the values in CHILD_NAME_DOB are:
<adam,15121990>
<roy,01051995>
<neha,05091992>
<alisha,11051992>
I am trying to fetch the last key element from CHILD_NAME_DOB. That is, I want to fetch key alisha from the example above to temporary String name.
Also I want to know on how to fetch data by index.
Eg.: if int index = 2 , I want key "Neha" in String name
TIA.
Edit: DateOfBirth value (value data in CHILD_NAME_DOB) is dynamic and is unknown. So THIS LINK is not what I want.
Single line solution:
First note that the Java HashMap does not guarantee the order of entries. So each time you iterate over a HashMap, entries appear in different positions. You will need LinkedHashMap that guarantees the predictable iteration order.
Map<String, String> CHILD_NAME_DOB = new LinkedHashMap<>();
Get the key by index:
key = (new ArrayList<>(CHILD_NAME_DOB.keySet())).get(index)
Get the value by index:
CHILD_NAME_DOB.get(key)
Thanks to #Pentium10 for this answer.
And I little modified it according to my need.
String key="default";
Iterator myVeryOwnIterator = CHILD_NAME_DOB.keySet().iterator();
while(myVeryOwnIterator.hasNext()) {
key=(String)myVeryOwnIterator.next();
//String value=(String)meMap.get(key);
}
Toast.makeText(viewEnterChildExp.getContext(), "Key: "+key , Toast.LENGTH_LONG).show();
I'm getting the last key element by this.
I'll update as soon I also get to find an easy way to key by index.
This way to get key....
public static String getHashMapKeyFromIndex(HashMap hashMap, int index){
String key = null;
HashMap <String,Object> hs = hashMap;
int pos=0;
for(Map.Entry<String, Object> entry : hs.entrySet())
{
if(index==pos){
key=entry.getKey();
}
pos++;
}
return key;
}
You can also use an ArrayMap instead of a HashMap. To get the value by index use:
ArrayMap.valueAt(index);
To get the Key at an index use:
ArrayMap.keyAt(index);
Fetching the "last" key and fetch by index is not supported by HashMap. You can use a LinkedHashMap and lookup the element with index 2 (or the last element) by iterating over it. But this will be a O(n) operation.
I suggest you use a List<Pair<String, String>> if the order of the keys/values is important to you and you wish to do index based lookup.
If both key based and index based lookup is important to you, you could use a combined data structure that consists of both a List and a HashMap, but note that removal of elements will be O(n).
You can create a class Child
public class Child(){
private String name;
private String number;
....
}
and then put this object in a List
public static List<Child> CHILD_NAME_DOB = new ArrayList<Child>(); // using LinkedList would defeat the purpose
in this way you can invoke the method get(int index), that returns the element at the specified position in this list.
In your example
<adam,15121990>
<roy,01051995>
<neha,05091992>
<alisha,11051992>
invoking CHILD_NAME_DOB.get(2) you'll get <neha,05091992>(as Child object)
HashMap does not have a concept of ordering, so getting the n-th entry does not make sense. You could use a TreeMap instead, which is ordered on its keys.
However, you should reconsider your model as you seem to have conflicting interests. On the one hand, accessing by index is typical for Lists, whereas accessing by key is typical for Maps. I'm not sure in which situation you'd want to do both.
If you really want to do both index and key accessing, you could write your own data structure that stores the data in a list combined with a mapping from key to index and vice versa. I would recommend against this, but if that's really what you want, then I think that's the best solution.
I know it is not the best solution, but what about this solution (pseudocode!). Just combine List and Map in one class.
public class UserBirthday {
private List<String> names = new ArrayList<>();
private Map<String, String> CHILD_NAME_DOB = new HashMap<String, String>();
public void add(String name, String bd) {
if (!CHILD_NAME_DOB.containsKey(name)) {
names.add(name);
}
CHILD_NAME_DOB.put(name, bd);
}
public String getByName(String name) {
return CHILD_NAME_DOB.get(name);
}
public String getByIndex(int index) {
return getByName(names.get(index)); // TODO: range test
}
public static void main(String[] args) {
UserBirthday ub = new UserBirthday();
ub.add("dit", "12345678");
ub.add("lea", "234239423");
ub.add("alex", "43534534");
ub.add("ted", "099098790");
System.out.println(ub.getByIndex(2));
System.out.println(ub.getByName("alex"));
}
}
You may get some problems if you remove an entry, but it should be just a suggestion.
for (String key : hmList.keySet()) {
String value = hmList.get(key);
Log.e("HashMap values", "key=" + key + " ,value=" + value);
}

Categories