How to Iterate Through Multiple Maps - java

So essentially, I have two hashmaps, one containing the following values:
rId33=image23
rId32=image22
rId37=image2
And the other containing this data:
{image2.jpeg=C:\Documents and Settings\image2.jpeg, image22.jpeg=C:\Documents and Settings\image22.jpeg, image23.jpeg=C:\Documents and Settings\image23.jpeg}
I basically want to be able to iterate through the first map, find a match of the key's, if a match is found, get the associated value, then look in the second map, find a match in the keys, then pull out the associated value (meaning the file path).
I was thinking of doing something like this for example (the follow is simplified)...
String val2 = "rId33";
for (String rID: map.keySet())
{
if (rID.contains(val2))
{
//enter code here
}
}
I was looking at the methods available for something like .getValue or something, but I'm not entirely sure how to do that. Any help would be appreciated. Thanks in advance for any replies.
Edited Code with Help From Bozho
else if ("v:imagedata".equals(qName) && headingCount > 0)
{
val2 = attributes.getValue("r:id");
String rID = imageMap.get(val2);
String path = imageLocation.get(rID + ".jpeg");
for (String rels: imageMap.keySet())
{
if (rels.contains(val2))
{
inImage = true;
image docImage = new image();
imageCount++;
docImage.setRelID(val2);
docImage.setPath(path);
addImage(docImage);
}
}

From what I see you don't need to iterate. Just:
String value1 = map1.get(key1);
if (value1 != null) {
String path = map2.get(value1 + ".jpeg");
}
If you don't always know whether it's value1 + ".jpeg", but you just know that the key starts with the first value, then you can iterate the 2nd map with:
for (Map.Entry<String, String> entry : map2.entrySet()) {
String key2 = entry.getKey();
String value2 = entry.getValue();
if (key.startsWith(value1)) {
return value2;
}
}
But note that the first code snippet is O(1) (both operations take constant time), while the 2nd is O(n)
And to answer the question as it is formulated in the title:
Get the iterators of both maps, and use it1.next() and it2.next() within a while loop. If any of the maps doesn't have more elements (it.hasNext()) - break.

That seems very inefficient. The entire point of a hash map is to do fast lookups. Do you really need to use that contains call on rID? In other words, can you change your hash map so that it directly contains the verbatim strings you want to search for and not just strings that contain the strings you want to search for as substrings? If yes, you could then use the answer given already. If not and if you must work with these data structures for whatever reason, the way to do what you're trying to do is something like:
String val2 = "rId33";
String path;
for (String rID: map.keySet())
{
if (rID.contains(val2))
{
path = secondMap.get(map.get(rID)+".jpeg");
break;
}
}
if (path == null)
{
//value not found
}

Related

How do I handle duplicate keys in HashMaps in Java?

I have a HashMap. I wrote a method for reading files and printing them, but I just thought that HashMap does not tolerate duplicate keys in the file, so I need to do something about it, e.g. saving the same key but with some kind of a character in the end (like just _ or something like that so they differ from each other). I can't come up with the solution (maybe I could catch an exception of just write an if-block). Could you please help me?
public static HashMap<String, String> hashmapReader(File test3) {
HashMap<String, String> data = new HashMap<>();
try (BufferedReader hmReader = new BufferedReader(new FileReader(test3))) {
String line;
while ((line = hmReader.readLine()) != null) {
String[] columns = line.split("\t");
String key = columns[0];
String value = columns[1];
data.put(key, value);
}
} catch (Exception e) {
System.out.println("Something went wrong");
}
return data;
}
You can add a control on the key if it already exist in the HashMap data.
In order to do this you can use get(key) method of the HashMap Java Class which returns null if the key doesn't exist:
if(data.get(key) != null)
key = key + "_";
data.put(key, value); //adding the split line array to the ArrayList
If it already exists (didn't return null) then you can change his name by adding a character at the end, e.g. "_" as you said.
EDIT: The answer above mine pointed out to me a fact: "What if there are more than 2 identical keys?".
For this reason, I recommend following his solution instead of mine.
To achieve what you actually ask for:
Before your put line:
while (data.containsKey(key)) key += "_";
data.put(key, value);
This will keep on checking the map to see if key already exists, and if it does, it adds the _ to the end, and tries again.
You can do these two lines in one:
while (data.putIfAbsent(key, value) != null) key += "_";
This does basically the same, but it just avoids having to look up twice in the case that the key isn't found (and thus the value should be inserted).
However, consider whether this is actually the best thing to do: how will you then look up things by "key", if you've essentially made up the keys while reading them.
You can keep multiple values per key by using a value type which stores multiple values, e.g. List<String>.
HashMap<String, List<String>> data = new HashMap<>();
// ...
data.computeIfAbsent(key, k -> new ArrayList<>()).add(value);

Foreach Key/Value pair issue

I'm trying to convert a PHP script into a Java one but coming across a few issues on a foreach loop. In the PHP script I have a foreach that takes the key:value pair and based off this does a str_replace.
foreach ($pValues AS $vKey => $vValue)
$vString = str_replace("{".$vKey."}", "'".$vValue."'", $vString);
I tried replicating this in Java without success. I need to get the key from the array to use in the string replace function, but can't find out where or if it's possible to get the key name from the array passed in.
Is this the right way or am I completely off? Should I be using the ImmutablePair method?
for (String vKey : pValues)
// String replace
Here's hoping there is an easy way to get the key:value pair in Java.
This can be acheived by using Map as data structure and then using entryset for iterating over it.
Map<K,V> entries= new HashMap<>();
for(Entry<K,V> entry : entries.entrySet()){
// you can get key by entry.getKey() and value by entry.getValue()
// or set new value by entry.setValue(V value)
}
That is not possible with a simple foreach-loop in Java.
If pValues is an array, you could use a simple for-loop:
for (int i = 0; i < pValues.length; i++)
// String replace
If pValues is a Map, you can iterate through it like this:
for (Key key : map.keySet())
string.replace(key, map.get(key));
Group Totals
Have the function GroupTotals(strArr) read in the strArr parameter containing key:value pairs where the key is a string and the value is an integer. Your program should return a string with new key:value pairs separated by a comma such that each key appears only once with the total values summed up.
For example: if strArr is ["B:-1", "A:1", "B:3", "A:5"] then your program should return the string A:6,B:2.
Your final output string should return the keys in alphabetical order. Exclude keys that have a value of 0 after being summed up.
Thanks all for the help and advice, I've managed to duplicate the function in Java using Map.
if (pValues != null)
{
Set vSet = pValues.entrySet();
Iterator vIt = vSet.iterator();
while(vIt.hasNext())
{
Map.Entry m =(Map.Entry)vIt.next();
vSQL = vSQL.replace("{" + (String)m.getKey() + "}", "'" + (String)m.getValue() + "'");
vSQL = vSQL.replace("[" + (String)m.getKey() +"]", (String)m.getValue());
}
}

How do I implement a nested ArrayList and iterate through them in Android Java

I am trying to create a structure where there will be a list of multiple String values e.g. "0212" and I want to have three ArrayLists. The first ArrayList will take the first part of the value "02", the second will take the second part "1" and the third will take the third value "2". I then want to be able to iterate through the list of values so that I can find the specific one quicker as multiple values will have the same value for the first and second part of the value. I then want to link that to an object that has a value matching "0212". I hope that someone understands what I am trying to explain and if anyone can help me, I would much appreciate it. Thank you in advance.
This is the code that I have at the moment which matches the string value against the DataObject address value in the ArrayList:
public void setUpValues()
{
String otherString = "4210";
Iterator<DataObject> it = dataObjects.iterator();
while(it.hasNext())
{
DataObject currentDataObject = it.next();
if(currentDataObject.getAddress().equals(otherString))
{
System.out.println("IT WORKSSSSSS!");
currentDataObject.setValue("AHHHHHHHHH");
System.out.println("Data Object Address: " + currentDataObject.getAddress());
System.out.println("Data Object Type: " + currentDataObject.getType());
System.out.println("Data Object Value: " + currentDataObject.getValue());
System.out.println("Data Object Range: " + currentDataObject.getRange());
}
else
{
}
}
}
Since the values are so tightly defined (three sections, each represented by one byte), I think you can build a lightweight solution based on Map:
Map<Byte, ArrayList<Byte>> firstSegments;
Map<Byte, ArrayList<Byte>> secondSegments;
Map<Byte, FinalObject> thirdSegments;
where FinalObject is the fully assembled data type (e.g., Byte[3]). This provides efficient lookup by segment, but you'll need to iterate over the arrays to find the "next" group of segments to check. Roughly:
Byte[3] needle = ...;
Byte firstSeg = ...;
Byte secondSeg = ...;
Byte thirdSeg = ...;
for (Byte b1 : firstSegments.get(firstSeg)) {
if (b1.equals(secondSeg)) {
for (Byte b2 : secondSegments.get(b1)) {
if (b2.equals(thirdSeg)) {
return thirdSegments.get(b2); // found a match
}
}
}
}
It's not clear from your question, but if you're trying to decide whether a given Byte segment is in one of the arrays and don't care about iterating over them, it would be cleaner and more efficient to use a Set<Byte> instead of ArrayList<Byte>. Set provides a fast contains() method for this purpose.

I have a query in mongodb and the reference key's are in hashmap list , I need to process a simple query using java in mongodb

mongodb query is db.test.find({"col1":{"$ne":""}}).count(), I have tried many sources to find the solution, the "col1" must be populated from list array, please help me
I have pasted a part of my code
`
List<String> likey = new ArrayList<String>();
for (DBObject o : out.results())
{
likey.add(o.get("_id").toString());
}
Iterator<String>itkey = likey.iterator();
DBCursor cursor ;
//cursor = table.find();
HashMap<String, String> hashmap = new HashMap<String, String>();
while (itkey.hasNext())
{
System.out.println((String)itkey.next());
String keys = itkey.next().toString();
//System.out.println("keys --> "+keys);
String nullvalue = "";
Boolean listone = table.distinct(keys).contains(nullvalue);
hashmap.put(keys, listone.toString());
//System.out.println("distinct --> "+keys+" "+listone);
//System.out.println("proper str --- >"+ '"'+keys+'"');
}
Iterator<String> keyIterator = hashmap.keySet().iterator();
Iterator<String> valueIterator = hashmap.values().iterator();
while (keyIterator.hasNext()) {
//System.out.println("key: " + keyIterator.next());
while (valueIterator.hasNext()) {
//System.out.println("value: " + valueIterator.next());
//System.out.println("Key: " + keyIterator.next() +""+"value: "+valueIterator.next());
String hashkey = valueIterator.next();
}
}
`
When you post code, it helps if you indent it, so it is more readable. As I mentioned to you on another forum, you need to go back and review the Java collection classes, since you have multiple usage errors in the above code.
Here are a few things you need to do to clean up your code:
1) You don't need to use the itkey iterator. Instead, use:
for (String key : likey)
and get rid of all the itkey.next calls. Your current code only processes every second element of the List. The other ones are printed out.
2) Your HashMap will map a key to a Boolean. Is that what you want? You said you want to count the number of non-zero values for the key. So, the line:
Boolean listone = table.distinct(keys).contains(nullvalue);
is almost certainly in error.
3) When you iterate over the HashMap, you don't need the valueIterator. Instead, get the key (either from the keyIterator, or a variable you define using the simpler iterator syntax above), then use the key to get the matching value using hashmap.get(key).
This will not make your code work, but it will clean it up somewhat - at the moment it is difficult to understand what you are intending it to do.

How to code a Closest Match String search in a database query in Java?

My specific problem is related to an Android project but this is not a specific android question.
I am basically just trying to come up with a way I can query a database and return results not based on exact matches but based on similar terms even outside the scope of a search on whether a String "contains" the typed value.
So for example, lets say I have a entry called "Popeye's Catfish". And lets say somebody enters the term "P's CatSalmon" and are looking for that entry. I would like to return a query list that shows essentially a "most similar" match.
I admit I am a complete novice at database queries so there might be ready answers out there that I just can't find (I did look). There are a few ways I can think to do this:
I could break apart the search string and look for separate parts of each string in a "contains" search of the actual entry. For example I could break out "P" "Cat" and "Salmon" search all three and do some other code to find out what the best result is. However, I'm really not sure how I would code it so that the program could pick the best segments. How would it know to pick out "cat" for example without just iterating through every possibility (which is almost certainly not realistic)?
I could just let the users suffer for a while until tags exist. What I mean is, once the correct entry is found by the "proper" name, I could just let users tag it with associated names and then include that separate associated name in the search by later users.
I can't come up with anything better than that based on my current level of knowledge.
Thanks in advance for the help.
I'm guessing that this is some sort of find location app. So let's assume that the number of locations is small, say less than 200.
You would start by building a search that looks for the "words" that the user typed in the locations. In your example, we have "P's" and "CatSalmon". "CatSalmon won't match anything, and neither will "P's".
So you return something that looks like this:
Locations found for "P's CatSalmon"
-----------------------------------
No locations found. Try using different search terms.
So, our user types "P CatSalmon".
So you return all the locations that start with the letter P, then the locations that contain the letter P.
Something like this:
Locations found for "P CatSalmon"
---------------------------------
Popeye's Catfish
Public library
Hope Restaurant
...
Now, here's where it gets interesting.
When the user picks a location, you log the search term and the location selected.
In your example, the user would pick "Popeye's Catfish".
So later, you manually add this key value to a synonym map.
Key Value
--------- ----------
CatSalmon Catfish
Over time, your searches will get better because your users will define the synonyms.
So, to recap.
You search for locations that start with a word.
You search for locations that contain a word.
You look in the synonym map for synonyms, and you repeat the start / contain process with the synonym(s).
Start locations are displayed first, then contain locations.
Finally, you do all this work on the server with the database. You pass the sorted location list to the phone. Don't make the phone do all the work.
This is something I put together essentially highlighting the closest matched term with a query based on the number of sequential characters
public class SequenceMatches {
public static void main(String [] args)
{
HashMap<String, Integer> map = new HashMap<String, Integer>();
String query = "P's SalmonCat ";
map = addTermsToHashMap(map);// add terms to a hash map
map = compareFirstCharacter(map, query);// compare the initial first character
map= compareSequentialCharacters(map, query);// compare terms to query and add score based on the number of matches
printResults(map);
}
public static HashMap<String,Integer> addTermsToHashMap(HashMap<String,Integer> map){
String term = "Popeye's CatFish";
String otherTerm = "Popets CatSalmon";
map.put(term,0);
map.put(otherTerm,0);
return map;
}
public static HashMap<String,Integer> compareFirstCharacter(HashMap<String,Integer> map,String query){
for(Map.Entry<String,Integer> e: map.entrySet())
{
String term = e.getKey();
char [] termChar = term.toCharArray();
char [] queryChar = query.toCharArray();
if((queryChar[0]) == (termChar[0]))
{
int value = map.get(term);
map.put(term,++value);
}
}
return map;
}
public static HashMap<String,Integer> compareSequentialCharacters(HashMap<String,Integer> map,String query){
for(Map.Entry<String,Integer> e: map.entrySet())
{
String term = e.getKey();
char [] termChar = term.toCharArray();
char [] queryChar = query.toCharArray();
for(int i = 0; i < queryChar.length -1; i++)
{
for(int j = 0; j < termChar.length -1; j++)
{
if(queryChar[i] == termChar[j] )
{
if((queryChar[i + 1]) == (termChar[j + 1]))
{
System.out.println((queryChar[i + 1]) + " " + (termChar[j + 1]));
int value = map.get(term);
map.put(term,++value);
break;
}
}
}
}
}
return map;
}
public static void printResults(HashMap<String,Integer> map)
{
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey()+" : "+entry.getValue());
}
}
}

Categories