How to find a key in a multiple-value HashMap? - java

my task is to make a synonym dictionary using HashMaps and Sets.
I have the following code in my main method:
public static void main(String[] args) {
addSynonym("casa", "imobil");
addSynonym("casa", "cladire");
addSynonym("casa", "locuinta");
addSynonym("casa", "camin");
addSynonym("casa", "domiciuliu");
addSynonym("jucarie", "joc");
addSynonym("jucarie", "marioneta");
addSynonym("jucarie", "papusa");
addSynonym("jucarie", "pantin");
addSynonym("om", "barbat");
addSynonym("om", "persoana");
afisarearray(getSynonyms("camin"));
}
One Method to insert the synonyms and the keys:
static Map<String, ArrayList<String>> synonymTable = new HashMap<String, ArrayList<String>>();
public static void addSynonym(String word, String synonym) {
ArrayList<String> checklist = synonymTable.get(word);
if (checklist == null) {
ArrayList<String> temporarylist = new ArrayList<String>();
temporarylist.add(synonym);
synonymTable.put(word, temporarylist);
} else {
synonymTable.get(word).add(synonym);
}
}
One Method to display an ArrayList:
public static void afisarearray(ArrayList<String> list) {
if (list != null) {
for (String s : list) {
System.out.println(s + "\n");
}
} else {
System.out.println("Empty list");
}
};
I want to find all the synonyms of a word for example the word "camin". And I wrote the following Method to do it, but it's not working, it is returning an empty set of keys:
public static ArrayList<String> getSynonyms(String word) {
if (word == "") {
System.out.println("No word to serach for ");
return null;
} else {
Set<String> keySet = new HashSet<String>();
for (Map.Entry<String, ArrayList<String>> entry : synonymTable.entrySet()) {
if (entry.getValue().equals(word)) {
keySet.add(entry.getKey());
}
}
if (keySet.isEmpty()) {
System.out.println("No keys found");
return null;
} else {
ArrayList<String> newlist = new ArrayList<String>();
for (String s : keySet) {
newlist.addAll(synonymTable.get(s));
}
return newlist;
}
}
}
The problem is inside this if:
if (entry.getValue().equals(word))
is a comparison between an ArrayList and a string.
I don't know how to correct it.

Try this, I also cleaned up your code a bit for readability
public static List<String> getSynonyms(String word) {
if (word == null || word.trim().isEmpty()) {
System.out.println("No word to serach for ");
return null;
}
Set<String> keySet = new HashSet<String>();
for (Map.Entry<String, List<String>> entry : synonymTable.entrySet()) {
if (entry.getValue().contains(word)) {
keySet.add(entry.getKey());
}
}
if (keySet.isEmpty()) {
System.out.println("No keys found");
return null;
}
//de-dupe and sort
Collection<String> terms = new TreeSet<>();
for (String s : keySet) {
terms.addAll(synonymTable.get(s));
}
return new ArrayList<>(terms);
}

Related

split strings with backtracking

I'm trying to write a code that split a spaceless string into meaningful words but when I give sentence like "arealways" it returns ['a', 'real', 'ways'] and what I want is ['are', 'always'] and my dictionary contains all this words. How can I can write a code that keep backtracking till find the best matching?
the code that returns 'a', 'real', 'ways':
splitter.java:
public class splitter {
HashMap<String, String> map = new HashMap<>();
Trie dict;
public splitter(Trie t) {
dict = t;
}
public String split(String test) {
if (dict.contains(test)) {
return (test);
} else if (map.containsKey(test)) {
return (map.get(test));
} else {
for (int i = 0; i < test.length(); i++) {
String pre = test.substring(0, i);
if (dict.contains(pre)) {
String end = test.substring(i);
String fixedEnd = split(end);
if(fixedEnd != null){
map.put(test, pre + " " + fixedEnd);
return pre + " " + fixedEnd;
}else {
}
}
}
}
map.put(test,null);
return null;
}
}
Trie.java:
public class Trie {
public static class TrieNode {
private HashMap<Character, TrieNode> charMap = new HashMap<>();
public char c;
public boolean endOWord;
public void insert(String s){
}
public boolean contains(String s){
return true;
}
}
public TrieNode root;
public Trie() {
root = new TrieNode();
}
public void insert(String s){
TrieNode p = root;
for(char c : s.toCharArray()) {
if(! p.charMap.containsKey(c)) {
TrieNode node = new TrieNode();
node.c = c;
p.charMap.put(c, node);
}
p = p.charMap.get(c);
}
p.endOWord = true;
}
public boolean contains(String s){
TrieNode p = root;
for(char c : s.toCharArray()) {
if(!p.charMap.containsKey(c)) {
return false;
}
p = p.charMap.get(c);
}
return p.endOWord;
}
public void insertDictionary(String filename) throws FileNotFoundException{
File file = new File(filename);
Scanner sc = new Scanner(file);
while(sc.hasNextLine())
insert(sc.nextLine());
}
public void insertDictionary(File file) throws FileNotFoundException{
Scanner sc = new Scanner(file);
while(sc.hasNextLine())
insert(sc.nextLine());
}
}
WordSplitter class:
public class WordSplitter {
public static void main(String[] args) throws FileNotFoundException {
String test = "arealways";
String myFile = "/Users/abc/Desktop/dictionary.txt";
Trie dict = new Trie();
dict.insertDictionary(myFile);
splitter sp = new splitter(dict);
test = sp.split(test);
if(test != null)
System.out.println(test);
else
System.out.println("No Splitting Found.");
}
}
Using the OP's split method and the implementation of Trie found in The Trie Data Structure in Java Baeldung's article, I was able to get the following results:
realways=real ways
arealways=a real ways
However, if I remove the word "real" or "a" from the dictionary, I get the following results:
realways=null
arealways=are always
Here's the entire code I used to get these results:
public class Splitter {
private static Map<String, String> map = new HashMap<>();
private Trie dict;
public Splitter(Trie t) {
dict = t;
}
/**
* #param args
*/
public static void main(String[] args) {
List<String> words = List.of("a", "always", "are", "area", "r", "way", "ways"); // The order of these words does not seem to impact the final result
String test = "arealways";
Trie t = new Trie();
for (String word : words) {
t.insert(word);
}
System.out.println(t);
Splitter splitter = new Splitter(t);
splitter.split(test);
map.entrySet().forEach(System.out::println);
}
public String split(String test) {
if (dict.find(test)) {
return (test);
} else if (map.containsKey(test)) {
return (map.get(test));
} else {
for (int i = 0; i < test.length(); i++) {
String pre = test.substring(0, i);
if (dict.find(pre)) {
String end = test.substring(i);
String fixedEnd = split(end);
if (fixedEnd != null) {
map.put(test, pre + " " + fixedEnd);
return pre + " " + fixedEnd;
} else {
}
}
}
}
map.put(test, null);
return null;
}
public static class Trie {
private TrieNode root = new TrieNode();
public boolean find(String word) {
TrieNode current = root;
for (int i = 0; i < word.length(); i++) {
char ch = word.charAt(i);
TrieNode node = current.getChildren().get(ch);
if (node == null) {
return false;
}
current = node;
}
return current.isEndOfWord();
}
public void insert(String word) {
TrieNode current = root;
for (char l : word.toCharArray()) {
current = current.getChildren().computeIfAbsent(l, c -> new TrieNode());
}
current.setEndOfWord(true);
}
#Override
public String toString() {
return toString(root);
}
/**
* #param root2
* #return
*/
private String toString(TrieNode node) {
return node.toString();
}
public static class TrieNode {
private Map<Character, TrieNode> children = new HashMap<>() ;
private String contents;
private boolean endOfWord;
public Map<Character, TrieNode> getChildren() {
return children;
}
public void setEndOfWord(boolean endOfWord) {
this.endOfWord = endOfWord;
}
public boolean isEndOfWord() {
return endOfWord;
}
#Override
public String toString() {
StringBuilder sbuff = new StringBuilder();
if (isLeaf()) {
return sbuff.toString();
}
children.entrySet().forEach(entry -> {
sbuff.append(entry.getKey() + "\n");
});
sbuff.append(" ");
return children.toString();
}
private boolean isLeaf() {
return children.isEmpty();
}
}
public void delete(String word) {
delete(root, word, 0);
}
private boolean delete(TrieNode current, String word, int index) {
if (index == word.length()) {
if (!current.isEndOfWord()) {
return false;
}
current.setEndOfWord(false);
return current.getChildren().isEmpty();
}
char ch = word.charAt(index);
TrieNode node = current.getChildren().get(ch);
if (node == null) {
return false;
}
boolean shouldDeleteCurrentNode = delete(node, word, index + 1) && !node.isEndOfWord();
if (shouldDeleteCurrentNode) {
current.getChildren().remove(ch);
return current.getChildren().isEmpty();
}
return false;
}
}
}
I improved the original code by adding a toString() method to the Trie and TrieNode. Now, when I print out the Trie object "t", I get the following result:
{a={r={e={a=}}, l={w={a={y={s=}}}}}, w={a={y={s=}}}}
My conclusion is that the OP's TrieNode implementation is incorrect. The way the Trie is built, given the inputted string value, the behavior described by the OP seems to be correct.

Simplify method with many for and Ifs statement

ExtractSourceQueryOB is an object that represents queries, a query could have a master query and in this case the master query should not be removed from the list, querySet contains strings of keys that represent queries that are required in this operation but it doesnt take account of the possibility of that query having a master. So i tried to loop through all queries checking that query has a master and in that case add that object (ExtractSourceQueryOB ) to the final list.
private List<ExtractSourceQueryOB> checkRequiredQueries(List<ExtractSourceQueryOB> extractSourceQueryList, ExtractElement extractElement) {
Set<ExtractSourceQueryOB> queryList = new HashSet();
Set<String> querySet = new HashSet();
fillUsedSymbolList(querySet, extractElement);
for(ExtractSourceQueryOB extractSourceQuery : extractSourceQueryList) {
if(extractSourceQuery.getMaster() != null ) {
for(ExtractSourceQueryOB extractSourceQuery2 : extractSourceQueryList) {
if(extractSourceQuery.getMaster().equals(extractSourceQuery2.getSymbol())){
queryList.add(extractSourceQuery2);
}
}
}
}
for (ExtractSourceQueryOB extractSourceQuery : extractSourceQueryList) {
for (String s : querySet) {
if (extractSourceQuery.getSymbol().equalsIgnoreCase(s)) {
queryList.add(extractSourceQuery);
}
}
}
return new ArrayList<>(queryList);
}
How can i simplify this method ?
You could eliminate the second for by combining that code with the first. Like,
for(ExtractSourceQueryOB extractSourceQuery : extractSourceQueryList) {
if(extractSourceQuery.getMaster() != null ) {
for(ExtractSourceQueryOB extractSourceQuery2 : extractSourceQueryList) {
if(extractSourceQuery.getMaster().equals(extractSourceQuery2.getSymbol())){
queryList.add(extractSourceQuery2);
}
}
}
for (String s : querySet) {
if (extractSourceQuery.getSymbol().equalsIgnoreCase(s)) {
queryList.add(extractSourceQuery);
}
}
}
private List<ExtractSourceQueryOB> checkRequiredQueries(List<ExtractSourceQueryOB> extractSourceQueryList, ExtractElement extractElement) {
Set<ExtractSourceQueryOB> queryList = new HashSet();
Set<String> querySet = new HashSet();
fillUsedSymbolList(querySet, extractElement);
for (ExtractSourceQueryOB extractSourceQuery : extractSourceQueryList) {
if (isyUsedAsMaster(extractSourceQuery,extractSourceQueryList) || isUsed(extractSourceQuery,querySet, extractSourceQueryList)) {
queryList.add(extractSourceQuery);
}
}
return new ArrayList<>(queryList);
}
private boolean isyUsedAsMaster(ExtractSourceQueryOB extractSourceQuery, List<ExtractSourceQueryOB> extractSourceQueryList) {
if (extractSourceQuery.getMaster() != null) {
for (ExtractSourceQueryOB extractSourceQuery2 : extractSourceQueryList) {
if (extractSourceQuery.getMaster().equals(extractSourceQuery2.getSymbol())) {
return true;
}
}
}
return false;
}
private boolean isUsed(ExtractSourceQueryOB extractSourceQuery, Set<String> querySet, List<ExtractSourceQueryOB> extractSourceQueryList) {
for (String s : querySet) {
if(extractSourceQuery.getSymbol().equalsIgnoreCase(s)) {
return true;
}
}
return false;
}
Previous answer above is correct but this is with some refactoring

Get values from below string using regex in java

I am a beginner to regex.
I have below String:
fail:2,success:1,fetch:1
Output Map: Get Map which contains all key-values as below:
fail - 2 (key=fail, value=2)
success - 1
fetch - 1
I have tried using below solution:
public static void main(String arg[]) {
String msg = "fail:1,success:1,policyfetch:1";
System.out.println(getKeyValuesFromMsg(msg));
}
public static Map getKeyValuesFromMsg(String msg) {
if (msg != null) {
Map keyvalues = new HashMap();
Pattern p = Pattern.compile("(\\w+):(,+)");
Matcher m = p.matcher(msg);
while (m.find()) {
keyvalues.put(m.group(1), m.group(2));
}
return keyvalues;
} else
return Collections.emptyMap();
}
You can use the split function, The following snippet should work fine
Map<String,String> map = new HashMap();
String str = "fail:2,success:1,fetch:1";
String[] keyValueParts = str.split(",");
for(String s : keyValueParts){
String parts[] = s.split(":");
map.put(parts[0],parts[1]);
}
System.out.println(map);
i would have used below method for the same.
public static void main(String arg[]) {
String msg = "fail:1,success:1,policyfetch:1";
System.out.println(getKeyValuesFromMsg(msg));
}
private static Map<Object, Object> getKeyValuesFromMsg(String msg) {
Map<Object,Object> mapObj = new HashMap<Object,Object>();
for (int i=0;i<msg.split(",").length;i++)
mapObj.put(msg.split(",")[i].split(":")[0],msg.split(",")[i].split(":")[1]);
return mapObj;
}
my solution:
public static Map<String, Integer> trans2Map(String source) {
if (null == source) {
return Collections.emptyMap();
}
Map<String, Integer> result = new HashMap<>();
Arrays.stream(source.split(","))
.filter(pair -> pair.split(":").length == 2)
.forEach(pair -> {
String key = pair.split(":")[0];
Integer value;
try {
value = Integer.parseInt(pair.split(":")[1]);
} catch (Exception e) {
return;
}
result.put(key, value);
});
return result;
}

How to copy value from one list to another list having different objects

I have MaterailInfo and StyleInfo, I want to set styleDescription based on StyleNumber matching with materialNumber. I am using 2 for loops, is there any alternative solution?
MaterailInfo:
class MaterailInfo {
private String materialNumber;
private String materialDescription;
public MaterailInfo(String materialNumber, String materialDescription) {
this.materialNumber = materialNumber;
this.materialDescription = materialDescription;
}
// getter setter methods
}
StyleInfo:
class StyleInfo {
private String StyleNumber;
private String styleDescription;
public StyleInfo(String styleNumber, String styleDescription) {
StyleNumber = styleNumber;
this.styleDescription = styleDescription;
}
// getter setter toString methods
}
TEst12:
public class TEst12 {
public static void main(String[] args) {
List<MaterailInfo> mList = new ArrayList<MaterailInfo>();
mList.add(new MaterailInfo("a", "a-desc"));
mList.add(new MaterailInfo("b", "b-desc"));
mList.add(new MaterailInfo("c", "c-desc"));
List<StyleInfo> sList = new ArrayList<StyleInfo>();
sList.add(new StyleInfo("a", ""));
sList.add(new StyleInfo("b", ""));
sList.add(new StyleInfo("c", ""));
for (MaterailInfo m : mList) {
for (StyleInfo s : sList) {
if (s.getStyleNumber().equals(m.getMaterialNumber())) {
s.setStyleDescription(m.getMaterialDescription());
}
}
}
System.out.println(sList);
}
}
If you use a Map instead of a List to store your data, you can get away with doing only a single loop:
Map<String, String> mMap = new HashMap<String, String>();
mMap.put("a", "a-desc");
mMap.put("b", "b-desc");
mMap.put("c", "c-desc");
Map<String, String> sMap = new HashMap<String, String>();
sMap.put("a", "");
sMap.put("b", "");
sMap.put("c", "");
for (Map.Entry<String, String> entry : mMap.entrySet()) {
sMap.put(entry.getKey(), mMap.get(entry.getKey());
}
This code will leave the style description empty if the style number does not match any known material number.
If your numbers can't have duplicates, using a HashMap instead of classes can be a bit faster.
import java.io.*;
import java.util.*;
import java.util.Map.Entry;
public class Demo {
public static void main(String[] args) {
HashMap<String, String> mList = new HashMap();
HashMap<String, String> sList = new HashMap();
mList.put("a", "a-desc");
mList.put("b", "b-desc");
mList.put("c", "c-desc");
sList.put("a", "");
sList.put("b", "");
sList.put("c", "");
Iterator entries = sList.entrySet().iterator();
while (entries.hasNext()) {
Entry entry = (Entry) entries.next();
if (mList.containsKey(entry.getKey())) {
sList.put((String) entry.getKey(), mList.get(entry.getKey()));
}
}
for (Map.Entry<String, String> entry : sList.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
}
}
You can do this using one for loop like this
for (int i = 0; i < mList.size(); i++) {
sList.get(i).setStyleDescription(mList.get(i).getMaterialDescription());
}
Note: i am assuming you have balanced lists in term of size.

How to delete these values from a hashtable?

in my scenario the hashTable is like this
AId=1
BId=1
catalogId=10053
reason_1=RET-KP
reason_2=RET-KP
quantity_1=1.0
ItemId_1=468504
quantity_2=1.0
ItemId_2=468505
Now i need to delete all _i things when reason_i=RET-KP
ie. delete ItemId_1 & quantity_1
Where reason_i is reason_1,reason_2
So how i can iterate this hashTable and delete the keys(dynamic) based on their values and storing it in hashTable again.
Check this will solve your problem .
package com.loknath.lab;
public class HashTableDemo {
public static void main(String args[]) {
Hashtable htable = new Hashtable(3);
boolean deleteStatus;
ArrayList<String> list = new ArrayList<String>();
// populate the table
htable.put("AId", 1);
htable.put(" catalogId", 2);
htable.put(" ItemId_1", 43);
htable.put("ItemId_2", 43);
htable.put("bid", 54.45);
Set<String> keys = htable.keySet();
for (String key : keys) {
System.out.println(key);
deleteStatus = check(key);
if (deleteStatus) {
list.add(key);
}
}
for (String string : list) {
htable.remove(string);
}
}
public static boolean check(String key) {
boolean status = false;
status = key.contains("_");
return status;
}
}

Categories