Java stream groupingby nested string - java

I have a list of string, and I want to be able to group them hierarchically.
Example of the list:
var list = new String[]{"caso.id",
"caso.unidadeDoCaso.id",
"caso.etiqueta",
"caso.sigiloso",
"caso.idPecaSegredoJustica",
"caso.numeroAno",
"caso.numero",
"caso.competencia.id",
"caso.competencia.ativo",
"caso.competencia.nome",
"caso.responsavel.id",
"caso.responsavel.dadosPessoais.nome",
"caso.escrivao.id",
"caso.escrivao.dadosPessoais.nome"};
I want to group them in Maps.
Like:
caso->
id
sigiloso,
...
unidadeDoCaso->
id
competencia->
id
ativo
...
responsavel->
id
dadosPessoais->
nome
...
...
...
I was able to group just one level. I was wondering if there's a way to do it recursively.

In spite of my suggestion I decided to provide this. There are two recursive routines.
one to fill the map.
the other to print it.
String[] array = {
"caso.id","caso.unidadeDoCaso.id","caso.etiqueta",
"caso.sigiloso","caso.idPecaSegredoJustica","caso.numeroAno",
"caso.numero","caso.competencia.id","caso.competencia.ativo",
"caso.competencia.nome","caso.responsavel.id",
"caso.responsavel.dadosPessoais.nome","caso.escrivao.id",
"caso.escrivao.dadosPessoais.nome"
};
Create the map
Then iterated across the data, splitting on the dot.
then call fill with the map, just split nodes, and the starting node index.
Map<String, Object> map = new HashMap<>();
for (String s : array) {
String[] nodes = s.split("\\.");
fill(map, nodes, 0);
}
print(map, "");
prints
caso
unidadeDoCaso
id
etiqueta
idPecaSegredoJustica
escrivao
id
dadosPessoais
nome
sigiloso
numero
id
numeroAno
responsavel
id
dadosPessoais
nome
competencia
ativo
nome
id
The fill method continues until the supplied nodes are all processed.
first the map is checked to see if the node exists or not(equal to null)
if not present, a new map is constructed and added to the supplied map. Then the method is called to process the next node.
otherwise, the method is called to add the current node to the map after the one that exists and continue processing the nodes.
public static void fill(Map<String, Object> map, String[] nodes, int i) {
if (i >= nodes.length) {
return;
}
String node = nodes[i];
#SuppressWarnings("unchecked")
Map<String, Object> obj = (Map<String, Object>)(node);
if (obj == null) {
Map<String, Object> m = new HashMap<>();
map.put(node, m);
fill(m, nodes, i + 1);
} else {
fill( obj, nodes, i + 1);
}
}
This prints the map elements and indents each subsequent nested map level on a separate line.
#SuppressWarnings("unchecked")
public static void print(Map<String, Object> map, String indent) {
for (String key : map.keySet()) {
if (key != null) {
System.out.println(indent + key);
print((Map<String, Object>) map.get(key), indent + " ");
}
}
}

Here is how you could do this using a Map<String, Map> and mutable reduction using the collect method that takes a supplier, accumulator, and combiner. The API is not the most pleasant to use, as WJS pointed out.
It requires unchecked casts because you can't represent these recursive structures of unknown depth using generics.
class Scratch {
public static void main(String[] args) {
var list = new String[]{"caso.id",
"caso.unidadeDoCaso.id",
"caso.etiqueta",
"caso.sigiloso",
"caso.idPecaSegredoJustica",
"caso.numeroAno",
"caso.numero",
"caso.competencia.id",
"caso.competencia.ativo",
"caso.competencia.nome",
"caso.responsavel.id",
"caso.responsavel.dadosPessoais.nome",
"caso.escrivao.id",
"caso.escrivao.dadosPessoais.nome"};
Map<String, Map> result = Arrays.stream(list).collect(HashMap::new, Scratch::mapRecursively, HashMap::putAll);
System.out.println(result);
// {caso={unidadeDoCaso={id=null}, etiqueta=null, idPecaSegredoJustica=null, escrivao={id=null, dadosPessoais={nome=null}}, sigiloso=null, numero=null, id=null, numeroAno=null, responsavel={id=null, dadosPessoais={nome=null}}, competencia={ativo=null, nome=null, id=null}}}
System.out.println(result.get("caso").keySet());
// [unidadeDoCaso, etiqueta, idPecaSegredoJustica, escrivao, sigiloso, numero, id, numeroAno, responsavel, competencia]
}
#SuppressWarnings("unchecked")
private static void mapRecursively(HashMap<String, Map> map, String s) {
// first recursion: s = caso.competencia.id
// second recursion: s = id
int dot = s.indexOf('.');
// Base case 1
if (dot == -1) {
map.put(s, null);
return;
}
String key = s.substring(0, dot); // caso
String value = s.substring(dot + 1); // competencia.id
boolean isFirstTimeToComeAcrossWord = !map.containsKey(key);
if (isFirstTimeToComeAcrossWord) {
map.put(key, new HashMap<>());
}
// Base case 2
int dot2 = value.indexOf('.');
if (dot2 == -1) {
map.get(key).put(value, null);
return;
}
String newKey = value.substring(0, dot2); // competencia
String leftover = value.substring(dot2 + 1); // id
boolean isFirstTimeWeComeAcrossNestedWord = !map.get(key).containsKey(newKey);
// Recursive cases
if (isFirstTimeWeComeAcrossNestedWord) {
var newMap = new HashMap<String, Map>();
map.get(key).put(newKey, newMap);
mapRecursively(newMap, leftover);
} else {
mapRecursively((HashMap<String, Map>) map.get(key).get(newKey), leftover);
}
}
}

Related

Converting delimited string/text into a map object

I have been trying to figure out a solution for a while now, but I can't seem to get any suitable answer after thinking through/surfing the net for a solution. Hope the community can help me out!
I have some string and wishes to convert them into a nested map object, example below.
Fruits.Apple.Red
Fruits.Apple.Green
Fruits.Orange.Yellow
Fruits.Watermelon.Yellow
Fruits.Watermelon.Red
I would like to convert the above example into something like this.
{ Fruits:{
Apple:{
Red: null,
Green: null
},
Orange:{
Yellow: null
},
Watermelon:{enter code here
Yellow: null,
Red: null
}
}
}
Pardon me if you find this example to be a bad one. There is a reason why the value for the last child is null, I am trying to reproduce the problem I am facing.
A recursive function addToMap may be implemented to find the key before the dot . as a delimiter, creating a map if necessary using Map::computeIfAbsent, or adding the key with null value to the top-level map:
#SuppressWarnings({"rawtypes", "unchecked"})
static void addToMap(String s, Map<String, Map> upperLevel) {
int dotPos = s.indexOf(".");
if (dotPos < 0) {
upperLevel.put(s, null);
} else {
String key = s.substring(0, dotPos);
addToMap(s.substring(dotPos + 1), upperLevel.computeIfAbsent(key, k -> new HashMap<>()));
}
}
Then the test may look as follows:
String[] arr = {
"Fruits.Cherry",
"Fruits.Apple.Red",
"Fruits.Apple.Green",
"Fruits.Orange.Yellow",
"Fruits.Watermelon.Yellow",
"Fruits.Watermelon.Red",
};
Map<String, Map> result = new HashMap<>();
for (String t : arr) {
addToMap(t, result);
}
System.out.println(result);
Output:
{Fruits={Apple={Red=null, Green=null}, Cherry=null, Watermelon={Red=null, Yellow=null}, Orange={Yellow=null}}}
If an insertion order is important, LinkedHashMap should be created instead of HashMap or an overridden version with Supplier<Map> may be used:
Supplier<Map> mapSupplier = LinkedHashMap::new;
Map<String, Map> result = mapSupplier.get();
for (String t : arr) {
addToMap(t, result, mapSupplier);
}
System.out.println(result);
#SuppressWarnings({"rawtypes", "unchecked"})
static void addToMap(String s, Map<String, Map> upperLevel, Supplier<Map> mapSupplier) {
int dotPos = s.indexOf(".");
if (dotPos < 0) {
upperLevel.put(s, null);
} else {
String key = s.substring(0, dotPos);
addToMap(s.substring(dotPos + 1), upperLevel.computeIfAbsent(key, k -> mapSupplier.get()), mapSupplier);
}
}
Output (order changed):
{Fruits={Cherry=null, Apple={Red=null, Green=null}, Orange={Yellow=null}, Watermelon={Yellow=null, Red=null}}}

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;
}
}
}
}

List of string with occurrences count and sort

I'm developing a Java Application that reads a lot of strings data likes this:
1 cat (first read)
2 dog
3 fish
4 dog
5 fish
6 dog
7 dog
8 cat
9 horse
...(last read)
I need a way to keep all couple [string, occurrences] in order from last read to first read.
string occurrences
horse 1 (first print)
cat 2
dog 4
fish 2 (last print)
Actually i use two list:
1) List<string> input; where i add all data
In my example:
input.add("cat");
input.add("dog");
input.add("fish");
...
2)List<string> possibilities; where I insert the strings once in this way:
if(possibilities.contains("cat")){
possibilities.remove("cat");
}
possibilities.add("cat");
In this way I've got a sorted list where all possibilities.
I use it like that:
int occurrence;
for(String possible:possibilities){
occurrence = Collections.frequency(input, possible);
System.out.println(possible + " " + occurrence);
}
That trick works good but it's too slow(i've got millions of input)... any help?
(English isn’t my first language, so please excuse any mistakes.)
Use a Map<String, Integer>, as #radoslaw pointed, to keep the insertion sorting use LinkedHashMap and not a TreeMap as described here:
LinkedHashMap keeps the keys in the order they were inserted, while a TreeMap is kept sorted via a Comparator or the natural Comparable ordering of the elements.
Imagine you have all the strings in some array, call it listOfAllStrings, iterate over this array and use the string as key in your map, if it does not exists, put in the map, if it exists, sum 1 to actual result...
Map<String, Integer> results = new LinkedHashMap<String, Integer>();
for (String s : listOfAllStrings) {
if (results.get(s) != null) {
results.put(s, results.get(s) + 1);
} else {
results.put(s, 1);
}
}
Make use of a TreeMap, which will keep ordering on the keys as specified by the compare of your MyStringComparator class handling MyString class which wraps String adding insertion indexes, like this:
// this better be immutable
class MyString {
private MyString() {}
public static MyString valueOf(String s, Long l) { ... }
private String string;
private Long index;
public hashcode(){ return string.hashcode(); }
public boolean equals() { // return rely on string.equals() }
}
class MyStringComparator implements Comparator<MyString> {
public int compare(MyString s1, MyString s2) {
return -s1.getIndex().compareTo(s2.gtIndex());
}
}
Pass the comparator while constructing the map:
Map<MyString,Integer> map = new TreeMap<>(new MyStringComparator());
Then, while parsing your input, do
Long counter = 0;
while (...) {
MyString item = MyString.valueOf(readString, counter++);
if (map.contains(item)) {
map.put(map.get(item)+1);
} else {
map.put(item,1);
}
}
There will be a lot of instantiation because of the immutable class, and the comparator will not be consistent with equals, but it should work.
Disclaimer: this is untested code just to show what I'd do, I'll come back and recheck it when I get my hands on a compiler.
Here is the complete solution for your problem,
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DataDto implements Comparable<DataDto>{
public int count = 0;
public String string;
public long lastSeenTime;
public DataDto(String string) {
this.string = string;
this.lastSeenTime = System.currentTimeMillis();
}
public boolean equals(Object object) {
if(object != null && object instanceof DataDto) {
DataDto temp = (DataDto) object;
if(temp.string != null && temp.string.equals(this.string)) {
return true;
}
}
return false;
}
public int hashcode() {
return string.hashCode();
}
public int compareTo(DataDto o) {
if(o != null) {
return o.lastSeenTime < this.lastSeenTime ? -1 : 1;
}
return 0;
}
public String toString() {
return this.string + " : " + this.count;
}
public static final void main(String[] args) {
String[] listOfAllStrings = {"horse", "cat", "dog", "fish", "cat", "fish", "dog", "cat", "horse", "fish"};
Map<String, DataDto> results = new HashMap<String, DataDto>();
for (String s : listOfAllStrings) {
DataDto dataDto = results.get(s);
if(dataDto != null) {
dataDto.count = dataDto.count + 1;
dataDto.lastSeenTime = System.nanoTime();
} else {
dataDto = new DataDto(s);
results.put(s, dataDto);
}
}
List<DataDto> finalResults = new ArrayList<DataDto>(results.values());
System.out.println(finalResults);
Collections.sort(finalResults);
System.out.println(finalResults);
}
}
Ans
[horse : 1, cat : 2, fish : 2, dog : 1]
[fish : 2, horse : 1, cat : 2, dog : 1]
I think this solution will be suitable for your requirement.
If you know that your data is not going to exceed your memory capacity when you read it all into memory, then the solution is simple - using a LinkedList or a and a LinkedHashMap.
For example, if you use a Linked list:
LinkedList<String> input = new LinkedList();
You then proceed to use input.add() as you did originally. But when the input list is full, you basically use Jordi Castilla's solution - but put the entries in the linked list in reverse order. To do that, you do:
Iterator<String> iter = list.descendingIterator();
LinkedHashMap<String,Integer> map = new LinkedHashMap<>();
while (iter.hasNext()) {
String s = iter.next();
if ( map.containsKey(s)) {
map.put( s, map.get(s) + 1);
} else {
map.put(s, 1);
}
}
Now, the only real difference between his solution and mine is that I'm using list.descendingIterator() which is a method in LinkedList that gives you the entries in backwards order, from "horse" to "cat".
The LinkedHashMap will keep the proper order - whatever was entered first will be printed first, and because we entered things in reverse order, then whatever was read last will be printed first. So if you print your map the result will be:
{horse=1, cat=2, dog=4, fish=2}
If you have a very long file, and you can't load the entire list of strings into memory, you had better keep just the map of frequencies. In this case, in order to keep the order of entry, we'll use an object such as this:
private static class Entry implements Comparable<Entry> {
private static long nextOrder = Long.MIN_VALUE;
private String str;
private int frequency = 1;
private long order = nextOrder++;
public Entry(String str) {
this.str = str;
}
public String getString() {
return str;
}
public int getFrequency() {
return frequency;
}
public void updateEntry() {
frequency++;
order = nextOrder++;
}
#Override
public int compareTo(Entry e) {
if ( order > e.order )
return -1;
if ( order < e.order )
return 1;
return 0;
}
#Override
public String toString() {
return String.format( "%s: %d", str, frequency );
}
}
The trick here is that every time you update the entry (add one to the frequency), it also updates the order. But the compareTo() method orders Entry objects from high order (updated/inserted later) to low order (updated/inserted earlier).
Now you can use a simple HashMap<String,Entry> to store the information as you read it (I'm assuming you are reading from some sort of scanner):
Map<String,Entry> m = new HashMap<>();
while ( scanner.hasNextLine() ) {
String str = scanner.nextLine();
Entry entry = m.get(str);
if ( entry == null ) {
entry = new Entry(str);
m.put(str, entry);
} else {
entry.updateEntry();
}
}
Scanner.close();
Now you can sort the values of the entries:
List<Entry> orderedList = new ArrayList<Entry>(m.values());
m = null;
Collections.sort(orderedList);
Running System.out.println(orderedList) will give you:
[horse: 1, cat: 2, dog: 4, fish: 2]
In principle, you could use a TreeMap whose keys contained the "order" stuff, rather than a plain HashMap like this followed by sorting, but I prefer not having either mutable keys in a map, nor changing the keys constantly. Here we are only changing the values as we fill the map, and each key is inserted into the map only once.
What you could do:
Reverse the order of the list using
Collections.reverse(input). This runs in linear time - O(n);
Create a Set from the input list. A Set garantees uniqueness.
To preserve insertion order, you'll need a LinkedHashSet;
Iterate over this set, just as you did above.
Code:
/* I don't know what logic you use to create the input list,
* so I'm using your input example. */
List<String> input = Arrays.asList("cat", "dog", "fish", "dog",
"fish", "dog", "dog", "cat", "horse");
/* by the way, this changes the input list!
* Copy it in case you need to preserve the original input. */
Collections.reverse(input);
Set<String> possibilities = new LinkedHashSet<String>(strings);
for (String s : possibilities) {
System.out.println(s + " " + Collections.frequency(strings, s));
}
Output:
horse 1
cat 2
dog 4
fish 2

java hash map 'cannot be resolved'. can execute methods but can't print

I have a program wherein a hash map, in the form of a tuple serving as the key (which represents a sentence read from an input file), and an integer (the number of times it was observed in the data) is capable of being populated with data but incapable of responding to my attempt to print it's contents. It's populated inside of the 'for' loop in the code below, and at the bottom of that snippet is where it's meant to print.
public static void main(String[] args) throws IOException
{
Ontology ontology = new Ontology();
BufferedReader br = new BufferedReader(new FileReader("/home/matthias/Workbench/SUTD/2_January/learning_first-order_horn_clauses_from_web_text/reverb/code/input_data/stackoverflow_test.txt"));
Pattern p = Pattern.compile("'(.*?)'\\('(.*?)',\\s*'(.*?)'\\)\\.");
String line;
while ((line = br.readLine()) != null)
{
Matcher m = p.matcher(line);
if( m.matches() )
{
String verb = m.group(1);
String object = m.group(2);
String subject = m.group(3);
ontology.addSentence( new Sentence( verb, object, subject ) );
}
}
for( String joint: ontology.getJoints() )
{
for( Integer subind: ontology.getSubjectIndices( joint ) )
{
Sentence xaS = ontology.getSentence( subind );
for( Integer obind: ontology.getObjectIndices( joint ) )
{
Sentence yOb = ontology.getSentence( obind );
Sentence s = new Sentence( xaS.getVerb(),
xaS.getObject(),
yOb.getSubject() );
//System.out.println( s );
ontology.numberRules( s );
}
}
}
for (Map.Entry<Sentence, Integer> entry : ontology.numberRules.entrySet())
{
System.out.println(entry.getKey()+" : "+entry.getValue());
}
}
The bottom of the following file is where the hash map is implemented. This also takes the input sentences and searches for overlapping values in the subject and object of sentences. What the system is trying to do is learn "rules" by inference from input data, i.e. contains(vitamin c, oranges), prevents(scurvy, vitamin c) would yeild the output prevents(scurvy, oranges), the thing is, in my test data there are many identical rules so i want to keep track of the number of times they're observed, while also storing only one copy of the unique "rule". which is why the hash map stores sentences as keys and integer (count) as value.
private List<Sentence> sentences = new ArrayList<>();
/*
* The following maps store the relation of a string occurring
* as a subject or object, respectively, to the list of Sentence
* ordinals where they occur.
*/
private Map<String,List<Integer>> subject2index = new HashMap<>();
private Map<String,List<Integer>> object2index = new HashMap<>();
/*
* This set contains strings that occur as both,
* subject and object. This is useful for determining strings
* acting as an in-between connecting two relations.
*/
private Set<String> joints = new HashSet<>();
public void addSentence( Sentence s )
{
// add Sentence to the list of all Sentences
sentences.add( s );
// add the Subject of the Sentence to the map mapping strings
// occurring as a subject to the ordinal of this Sentence
List<Integer> subind = subject2index.get( s.getSubject() );
if( subind == null )
{
subind = new ArrayList<>();
subject2index.put( s.getSubject(), subind );
}
subind.add( sentences.size() - 1 );
// add the Object of the Sentence to the map mapping strings
// occurring as an object to the ordinal of this Sentence
List<Integer> objind = object2index.get( s.getObject() );
if( objind == null )
{
objind = new ArrayList<>();
object2index.put( s.getObject(), objind );
}
objind.add( sentences.size() - 1 );
// determine whether we've found a "joining" string
if( subject2index.containsKey( s.getObject() ) )
{
joints.add( s.getObject() );
}
if( object2index.containsKey( s.getSubject() ) )
{
joints.add( s.getSubject() );
}
}
public Collection<String> getJoints()
{
return joints;
}
public List<Integer> getSubjectIndices( String subject )
{
return subject2index.get( subject );
}
public List<Integer> getObjectIndices( String object )
{
return object2index.get( object );
}
public Sentence getSentence( int index )
{
return sentences.get( index );
}
//map to store learned 'rules'
Map<Sentence, Integer> ruleCount = new HashMap<>();
//store data
public void numberRules(Sentence sentence)
{
if (!ruleCount.containsKey(sentence))
{
ruleCount.put(sentence, 0);
}
ruleCount.put(sentence, ruleCount.get(sentence) + 1);
}
This is the object for storing sentences.
public class Sentence
{
private String verb;
private String object;
private String subject;
public Sentence(String verb, String object, String subject )
{
this.verb = verb;
this.object = object;
this.subject = subject;
}
public String getVerb()
{
return verb;
}
public String getObject()
{
return object;
}
public String getSubject()
{
return subject;
}
public String toString()
{
return verb + "(" + object + ", " + subject + ").";
}
}
input data looks like this
'prevents'('scurvy','vitamin C').
'contains'('vitamin C','orange').
'contains'('vitamin C','sauerkraut').
'isa'('fruit','orange').
'improves'('health','fruit').
I hope output data can tell me, for instance
prevents(scurvy, orange). 2
prevents(scurvy, sauerkraut). 4
improves(health, orange). 1
Where the sentences are the key of the hash map and the integer is the associated value, corresponding to the number of times that sentence was observed in the data.
I don't see a numberRules member in your Ontology class.
Perhaps you meant to use the ruleCount member, which is the only variable of type Map<Sentence, Integer> I see in your code.
for (Map.Entry<Sentence, Integer> entry : ontology.ruleCount.entrySet())
{
System.out.println(entry.getKey()+" : "+entry.getValue());
}
Regarding Hector's comment, that's a different problem. When you use one of your custom classes as a key in a HashMap (Sentence class in your case), you must override equals and hashCode. If you don't a.equals(b) will return true only if a==b, which is probably not the behavior you desire. You probably want a.equals(b) to return true when the verb, object and subject of the two compared sentences are equal to each other respectively. hashCode should be implemented in a way that if a.equals(b) is true, a.hashCode() == b.hashCode().

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);

Categories

Resources