edit hashmap with hashset as value - java

I have the following code:
HashMap<String, HashSet<Person>> index = new HashMap<String, HashSet<Person>>();
public static void indexDB(String base)
{
for(Person i: listB)
{
if(name.equals(base))
{
}
}
listB is an array with Person elements.
So, if a Person's name matches the String base, they are getting attached to a pair of key-value in the index HashMap. The HashSet for each key contains the Persons that their name matches the String base. How can this be done?
Also, I have a method like:
public void printPersons(String sth)
{
}
that I want it to print the persons contained in the HashSet of the key called each time.
Thank you

Use putIfAbsent to insert an empty hash set place holder.
Then add new person to existing set:
HashMap<String, HashSet<Person>> index = new HashMap<String, HashSet<Person>>();
public static void indexDB(String base)
{
for(Person i: listB)
{
if(name.equals(base))
{
index.putIfAbsent(base, new HashSet<>());
index.get(base).add(i)
}
}
Note: In order to correctly add person to set, you have to implement equals()/hashCode() for your Person class, since Set use equals() to determine uniqueness

Instead of creating HashSet object in every iteration, create it only when name matches like in the below code -
public static void indexDB(String base)
{
for(Person i: listB)
{
if(index.containsKey(base)){
HashSet<Person> existingHS = index.get(base);
existingHS.add(i);
index.put(base,existingHS);
}else{
HashSet<Person> hs = new HashSet<Person>();
hs.add(i);
index.put(base,hs);
}
}

Do this
HashMap<String, HashSet<Person>> index = new HashMap<String, HashSet<Person>>();
public static void indexDB(String base)
{
HashSet<Person> h = new HashSet<String>();
for(Person i: listB)
{
//I assume it is i.name here
if(i.name.equals(base))
{
h.add(i);
}
}
index.put(base,h);
}
And for printing, do this
public void printPersons(String sth)
{
Map mp = index.get(sth);
Iterator it = mp.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
System.out.println(pair.getKey() + " = " + pair.getValue());
}
}

Related

Iterate Map in Java

Entry which needs to compare with the List and get the value from Map which is not there is the List.
for (Map.Entry<String, Object> entry : itemObj.entrySet())
{
System.out.println(entry.getKey());
for (ItemProcessVO processVO : itemDetails2){
if (entry.getKey().equalsIgnoreCase(processVO.getAccount())){
String account = processVO.getAccount();
lstAccVO.add(account);
}
}
}
This is the code i have used.I have Map of entry.getKey() has 6 Values while itemDetail2 has only 5 elements.I need to display only the missing account after comparing.
Simply add an else-statement to your if clause that stores that account in a local variable. Then after your for loops you can do whatever with that.
Hint: you can use loop over Map#keySet() instead of Map#entrySet() and bypass the entries that way.
In the provided example you compared the key with the account, simply use the else- statement to find the missingAccounts to iterate after this loop over them.
List<ItemProcessVO> missingAccounts= new ArrayList<>();
for (Map.Entry<String, Object> entry : itemObj.entrySet())
{
System.out.println(entry.getKey());
for (ItemProcessVO processVO : itemDetails2){
if (entry.getKey().equalsIgnoreCase(processVO.getAccount())){
String account = processVO.getAccount();
lstAccVO.add(account);
}else{
missingAccounts.add(account)
}
}
}
Below code should do the trick. It uses case insensitive comparison and prints remaining keys in the end, more explanation is in comments:
public static void main(String[] args) throws IOException {
Map<String, Object> itemObj = new HashMap<>(); //Your Map
List<ItemProcessVO> itemDetails2 = new ArrayList<>();// Your list
//First, get all the keys of the map
Set<String> keys = new HashSet<>(itemObj.keySet());
//Now, iterate through list and remove the matching items
for(ItemProcessVO processVO : itemDetails2){
String key = pop(keys, processVO.getAccount());
//If key is not null then remove it
if(null != key){
keys.remove(key);
}
}
//Now, iterate through remaining keys and print the values
for(String key : keys){
System.out.println("Missing value " + itemObj.get(key));
}
}
private static String pop(Set<String> set, String key){
if(null == set){
return null;
}else{
for(String element : set){
if(element.equalsIgnoreCase(key)){
return element;
}
}
}
}

Java HashMap, get(key) method doesnt work

I'm trying to create a PhoneBook class that uses a HashMap in Java. When I add an entry using the put() method in addContact(), it works fine, but when I try to retrieve values in the searchContact() method, none are returned. I'm not getting null values; HashMap definitely contains the key(s) I am searching for, but the values associated with the key(s) are not being returned. Thank you in advance.
Here is my code:
public class PhoneBookContactsImpl {
private Map<String, List<String>> contactMap = new HashMap<String, List<String>>();
public void addContact(String name, List<String> list) {
contactMap.put(name, list);
//its working fine here
System.out.println(contactMap.get(name));
}
public Map<String, List<String>> getContactMap() {
Set set = contactMap.entrySet();
Iterator i = contactMap.entrySet().iterator();
while (i.hasNext()) {
Map.Entry me = (Map.Entry) i.next();
System.out.println(me.getKey() + " : ");
List<String> nos = (List<String>) me.getValue();
System.out.println("Nos = " + nos + " n ");
System.out.println(nos.size());
}
return contactMap;
}
public List<String> searchContact(String name) throws NoDataFoundException {
if (contactMap.isEmpty()) {
System.out.println("Empty PhoneBook");
throw new NoDataFoundException();
} else {
if (contactMap.containsValue(name))
return contactMap.get(name);
//it doesnt retrieve valur from here
else {
System.out.println("No Entry for Specified Entry");
throw new NoDataFoundException();
}
}
}
}
your if statement is checking if the phonebook has name as a value, so your get is never reached.
Try this:
if (contactMap.containsKey(name))
return contactMap.get(name);
As the other answer points out you should be checking containsKey because name is a key, not a value. But why not make the whole thing much easier:
public List<String> searchContact(String name) throws NoDataFoundException {
List<String> result = contactMap.get(name);
if (result == null) {
// empty map, or no matching value or value is null
throw new NoDataFoundException();
}
}
You are doing:
if (contactMap.containsValue(name))
return contactMap.get(name);
and you need to do:
if (contactMap.containsKey(name))
return contactMap.get(name);

Java Filtering in collections

I have a list of objects as below,
Emp e1 = new Emp(10,"Anitha",1000,"AE");
Emp e2 = new Emp(20,"Chaitanya",2000,"SE");
Emp e3 = new Emp(30,"Chaitanya",3000,"SE");
Emp e4 = new Emp(40,"Deepthi",2100,"AE");
Emp e5 = new Emp(50,"Deepthi",2200,"CE");
Emp e6 = new Emp(60,"Deepthi",2300,"BE");
Emp e7 = new Emp(70,"Anitha",2300,"BE");
Emp e8 = new Emp(80,"Anitha",2400,"ME");
Emp e9 = new Emp(90,"Sita",2200,"CE");
Emp e10 = new Emp(100,"Hari",2200,"CE");
Emp e11 = new Emp(110,"Krishna",2200,"CE");
I would like to filter the values on unique name and also filter on same name like
1.on unique name : output should be
(50,"Deepthi",2200,"CE")
(100,"Hari",2200,"CE")
(110,"Krishna",2200,"CE")
and sharing the same name :
like output
(10,"Anitha",1000,"AE")
(70,"Anitha",2300,"BE")
(80,"Anitha",2400,"ME")
(20,"Chaitanya",2000,"SE");
(30,"Chaitanya",3000,"SE");
(40,"Deepthi",2100,"AE");
(50,"Deepthi",2200,"CE");
(60,"Deepthi",2300,"BE");
using collections....
Will some one be able to help me?
Thanks in Advance.
Nithya
If you're using java 8 please skip to the end!
I'd probably create a map to do this, but it seems like you're new to Java so I'll describe the more basic way.
You should first create a list(arraylist) like so:
// create an arraylist (list based on an array)
List<Emp> emps = new ArrayList<Emp>();
Then you can add objects to the list:
emps.add(new Emp(10,"Anitha",1000,"AE"));
emps.add(new Emp(20,"Chaitanya",2000,"SE"));
.
.
Now you can start filtering!
So, suppose you have a getName() method in class Emp, you can write a function such as this:
// this function takes a list and a name, and filters the list by the name
public static List<Emp> filterEmpsByName(List<Emp> emps, String name){
// a place to store the result
List<Emp> result = new ArrayList<Emp>();
// iterate over the list we got
for (Emp emp: emps){
// save only the elements we want
if (emp.getName().equals(name)){
result.add(emp);
}
}
return result;
}
Now, filtering would be a simple matter of calling that function:
// print to standard output the result of our function on the "main" list `emp` with name "Anitha"
for (Emp emp : filterEmpsByName(emps, "Anitha")){
System.out.println(emp.toString()); // make sure toString() is overridden in Emp class
}
Now for the second part which is a bit more tricky:
// this function takes a list and a name, and filters the list by the name
public static List<Emp> getDistinctlyNamedEmps(List<Emp> emps, String name) {
// this time we use a map which is A LOT faster for this kind of operation
Map<String, Emp> result = new HashMap<String, Emp>();
// iterate over the list we got
for (Emp emp : emps) {
// save only the elements we want
if (result.get(emp.getName()) == null ) {
result.put(emp.getName(), emp);
}
}
// convert map to list - not mandatory if you can use the map as is...
return new ArrayList<Emp>(result.values());
}
Notice that you can also write a comparator that compares objects using the name/any other property, but that's beyond the scope of this comment :-)
Putting the whole thing together:
Main class:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Main {
public static void main(String[] args) {
// create an [arraylist][4] (list based on an array)
List<Emp> emps = new ArrayList<Emp>();
emps.add(new Emp(10, "Anitha", 1000, "AE"));
emps.add(new Emp(20, "Chaitanya", 2000, "SE"));
// print to standard output the result of our function on the "main"
// list `emp` with name "Anitha"
System.out.println("filterEmpsByName(emps, \"Anitha\") output:");
for (Emp emp : filterEmpsByName(emps, "Anitha")) {
System.out.println(emp.toString()); // make sure toString() is
// overridden in Emp class
}
// print to standard output the result of our second function on the "main"
// list `emp`
System.out.println("getDistinctlyNamedEmps(emps) output:");
for (Emp emp : getDistinctlyNamedEmps(emps)) {
System.out.println(emp.toString()); // make sure toString() is
// overridden in Emp class
}
}
// this function takes a list and a name, and filters the list by the name
public static List<Emp> filterEmpsByName(List<Emp> emps, String name) {
// a place to store the result
List<Emp> result = new ArrayList<Emp>();
// iterate over the list we got
for (Emp emp : emps) {
// save only the elements we want
if (emp.getName().equals(name)) {
result.add(emp);
}
}
return result;
}
// this function takes a list and a name, and filters the list by the name
public static List<Emp> getDistinctlyNamedEmps(List<Emp> emps) {
// this time we use a map which is A LOT faster for this kind of
// operation
Map<String, Emp> result = new HashMap<String, Emp>();
// iterate over the list we got
for (Emp emp : emps) {
// save only the elements we want
if (result.get(emp.getName()) == null) {
result.put(emp.getName(), emp);
}
}
// convert map to list - not necessary
return new ArrayList<Emp>(result.values());
}
}
And partial Emp class:
public class Emp {
private String name;
public Emp(int stubi, String name, int j, String stubs) {
this.name = name;
}
public String getName() {
return this.name;
}
public String toString() {
return "[" + this.name + "]";
}
}
Java 8:
Java 8 has lambda expressions (anonymous functions), which are neat tools used in many other languages for filtering as well as other operations.
You can read more about using them here.
As far as I can see, the answers until now assumed that the task was to search for a particular name, or to find elements with unique names - and I think this was not what was asked for.
In order to filter a list in the way that is described in the original question, one could create a map from the "key" (that is, the 'name' in this case) to a list of elements that share this key. Using this map, one can easily find
One element for each key that occurs only once in all elements
The list of all elements that have a key that occurs at least twice in all elements
These tasks are rather similar, and further generalizations may be possible, but here is one way of how this may be implemented:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class CriterionFilter
{
public static void main(String[] args)
{
List<Emp> list = new ArrayList<Emp>();
list.add(new Emp(10,"Anitha",1000,"AE"));
list.add(new Emp(20,"Chaitanya",2000,"SE"));
list.add(new Emp(30,"Chaitanya",3000,"SE"));
list.add(new Emp(40,"Deepthi",2100,"AE"));
list.add(new Emp(50,"Deepthi",2200,"CE"));
list.add(new Emp(60,"Deepthi",2300,"BE"));
list.add(new Emp(70,"Anitha",2300,"BE"));
list.add(new Emp(80,"Anitha",2400,"ME"));
list.add(new Emp(90,"Sita",2200,"CE"));
list.add(new Emp(100,"Hari",2200,"CE"));
list.add(new Emp(110,"Krishna",2200,"CE"));
Function<Emp, String> keyFunction = new Function<Emp, String>()
{
#Override
public String apply(Emp s)
{
return s.getName();
}
};
List<Emp> fiteredOnUnique = filterOnUnique(list, keyFunction);
System.out.println("Filtered on unique:");
print(fiteredOnUnique);
List<Emp> filteredOnSame = filterOnSame(list, keyFunction);
System.out.println("Filtered on same:");
print(filteredOnSame);
}
private static void print(Iterable<?> elements)
{
for (Object element : elements)
{
System.out.println(element);
}
}
/**
* Create a map that maps the keys that are provided for the given
* elements to the list of elements that have this key
*
* #param elements The input elements
* #param keyFunction The key function
* #return The map
*/
private static <T, K> Map<K, List<T>> map(
Iterable<? extends T> elements, Function<? super T, K> keyFunction)
{
Map<K, List<T>> map = new HashMap<K, List<T>>();
for (T t : elements)
{
K key = keyFunction.apply(t);
List<T> list = map.get(key);
if (list == null)
{
list = new ArrayList<T>();
map.put(key, list);
}
list.add(t);
}
return map;
}
/**
* Uses the given key function to compute the keys associated with the
* given elements, and returns a list containing the element of
* the given sequence that have unique keys
*
* #param elements The input elements
* #param keyFunction The key function
* #return The filtered list
*/
private static <T, K> List<T> filterOnUnique(
Iterable<? extends T> elements, Function<? super T, K> keyFunction)
{
List<T> result = new ArrayList<T>();
Map<K, List<T>> map = map(elements, keyFunction);
for (Entry<K, List<T>> entry : map.entrySet())
{
List<T> list = entry.getValue();
if (list.size() == 1)
{
result.add(list.get(0));
}
}
return result;
}
/**
* Uses the given key function to compute the keys associated with the
* given elements, and returns a list containing all elements of
* the given sequence that have a key that occurs multiple times.
*
* #param elements The input elements
* #param keyFunction The key function
* #return The filtered list
*/
private static <T, K> List<T> filterOnSame(
Iterable<? extends T> elements, Function<? super T, K> keyFunction)
{
List<T> result = new ArrayList<T>();
Map<K, List<T>> map = map(elements, keyFunction);
for (Entry<K, List<T>> entry : map.entrySet())
{
List<T> list = entry.getValue();
if (list.size() > 1)
{
result.addAll(list);
}
}
return result;
}
/**
* Interface for a generic function
*/
static interface Function<S, T>
{
T apply(S s);
}
}
class Emp
{
private int i;
private String name;
private int j;
private String whatever;
public Emp(int i, String name, int j, String whatever)
{
this.i = i;
this.name = name;
this.j = j;
this.whatever = whatever;
}
#Override
public String toString()
{
return "Emp [i=" + i + ", name=" + name + ", j=" + j + ", whatever=" + whatever + "]";
}
String getName()
{
return name;
}
}
(EDIT: Adjusted the first case, see comment in original question)
Thats not a collections, while it is a 'list' in the traditional sense, it is not a java.util.ArrayList.
To do this, you might try:
ArrayList<Emp> employeeList = new ArrayList<Emp>();
employeeList.add(new Emp(10,"Anitha",1000,"AE"));
// repeat

Join two Lists in Java

I need to join two Lists in Java. I've a list which has a VO that has a name and description. I've another list which has same VO type that has name and Address. The "name" is same. I need to create a List with this VO which has both name, address and description.
The VO structure is
public class PersonDetails{
private String name;
private String description;
private String address;
//getters and setters
}
Can someone please suggest me the best way to implement it?
It depends:
If the lists contain both exactly the same data, you can sort them both by name, iterate over them en set the missing property.
If not, I would put the first list in a Map, with the name as key. Then iterate over the second list, look in the map for the VO and set the value.
After that, just get all the value's out of the map again as a List.
public List<Vo> merge(List<Vo> list1, List<Vo> list2) {
Map<String, Vo> tempMap = new HashMap<String, Vo>();
for (Vo v : list1) {
tempMap.put(v.name, v);
}
for (Vo vv : list2) {
//The if is in case the 2 lists aren't filled with the same objects
if (tempMap.containsKey(vv.name)) {
tempMap.get(vv.name).description = vv.description;
} else {
tempMap.put(vv.name, vv);
}
}
return new ArrayList<Vo>(tempMap.values());
}
If the lists contain both EXACT the same VO (equal by name), you can use this.
public List<Vo> merge(List<Vo> list1, List<Vo> list2) {
Collections.sort(list1, new Comparator<Vo>() {
public int compare(Vo o1, Vo o2) {
return o1.name.compareTo(o2.name);
}
});
Collections.sort(list2, new Comparator<Vo>() {
public int compare(Vo o1, Vo o2) {
return o1.name.compareTo(o2.name);
}
});
for(int i = 0; i < list1.size(); i++){
list1.get(i).description = list2.get(i).description;
}
return list1;
}
Put all elements of the first list in a map, then merge the contents of the second list into it:
final List<PersonDetails> listWithAddress =
new ArrayList<PersonDetails>();
final List<PersonDetails> listWithDescription =
new ArrayList<PersonDetails>();
// fill both lists with data
final Map<String, PersonDetails> map =
// map sorted by name, change to HashMap otherwise
// (or to LinkHashMap if you need to preserve the order)
new TreeMap<String, PersonDetails>();
for(final PersonDetails detailsWithAddress : listWithAddress){
map.put(detailsWithAddress.getName(), detailsWithAddress);
}
for(final PersonDetails detailsWithDescription : listWithDescription){
final PersonDetails retrieved =
map.get(detailsWithDescription.getName());
if(retrieved == null){
map.put(detailsWithDescription.getName(),
detailsWithDescription);
} else{
retrieved.setDescription(detailsWithDescription.getDescription());
}
}
I would put each list of the source VO lists in a map by name, create a set of both keys, iterate it and add a target VO to the result list.
In the example code, VO is the target VO, VOD is the source VO with description only, VOA is the source VO with address only:
List<VOD> descriptions = ...;
List<VOA> addresses = ...;
Map<String,String> description ByName = new HashMap<String,String>();
for (VOD description : descriptions) {
descriptionByName.put(description.name, description.description);
}
Map<String,String> addressByName = new HashMap<String,String>();
for (VOA address: addresses ) {
addressByName.put(address.name, address.address);
}
Set<String> allNames = new HashSet<String>();
allNames.addAll(descriptionByName.keySet());
allNames.addAll(addressByName.keySet());
List<VO> result = new ArrayList<VO>();
for (String name : allNames) {
VO one = new VO();
one.name = name;
one.address = addressByName.get(name)
one.description = descriptionByName.get(name)
result.add(one);
}
Go from list to HashMap, use the name string as key. So you can merge you data quite efficient.
List<VO> list = new ArrayList<VO>();
for (VO vo1 : vo1List) {
for (VO vo2 : vo2List) {
if (vo1.getName().equals(vo2.getName())) {
VO newVo = new VO();
newVO.setName(vo1.getName());
newVO.setDescription(vo1.getDescription());
newVO.setAddress(vo2.getAddress);
list.add(newVO);
break;
}
}
}
It's best that you sort both lists on name beforehand, it makes the double iteration faster.

java arraylist format

I am having one problem in java arraylist. I am good in databases :) We normally use
"group by" to group rows. I want the same thing but in java for one of my project
I have following format in arraylist
name1:val1
name1:val2
name1:val3
name2:val8
name2:val7
name7:val54
name7:val76
name7:val34
I want to convert this arraylist to give me following output:
-name1
val1
val2
val3
-name2
val8
val7
-name7
.
.
.
val34
this is not a school assignment :). may be for some of Java Guru it looks like a small
thing to do.
I like to do that kind of thing with a map.
import java.util.*;
public class DoIt {
public static void main(String[] args) {
List l = new ArrayList<String>();
l.add("name1:val1");
l.add("name1:val2");
l.add("name1:val3");
l.add("name1:val4");
l.add("name2:val1");
Map results = new HashMap<String,String>();
for (Iterator i = l.iterator(); i.hasNext();) {
String s = (String)i.next();
String[] tmp = s.split(":");
if (!results.containsKey(tmp[0])) {
System.out.println("-"+tmp[0]+"\n"+tmp[1]);
results.put(tmp[0], tmp[1]);
} else {
System.out.println(tmp[1]);
}
}
}
}
Use a Map<String, List<Integer>>. You could use the following snippets:
// declare
Map<String, List<Integer>> m = new HashMap<String, List<Integer>>();
// insert into the structure the pair 'a':2
List<Integer> l = m.get("a");
if ( l == null ) {
l = new ArrayList<Integer>();
m.put("a", l);
}
l.add(2);
// iterate over the values
for (Map<String, List<Integer>>.Entry e : m) {
System.out.println("-" + e.getKey());
for (Integer i : m.getValue()) {
System.out.println(" " + i);
}
}
What you are looking for is called multi-map.
There is no standard multi-map in java.util, but Google collections has implemented it -> here. The project home page is here
Use Comparator
List<Samp> bla = new ArrayList<Samp>();
Collections.sort(bla, new Comparator<Samp>() {
#Override
public int compare(Samp s1, Samp s2) {
return s1.getCategory().compareTo(s2.getCategory());
}
});
then Create 1 List .,. compare if that list already contains the category, if not,
add Category and Name, else just add Name. see code below :)
List<String> catList = new ArrayList<String>();
for(Samp s : bla){
if (!catList.contains(s.getCategory())){
catList.add(s.getCategory());
System.out.println(s.getCategory() + " - ");
System.out.println(s.getName());
} else {
System.out.println(s.getName());
}
}

Categories

Resources