I have the following code which adds some arrays to a hashmap but then I want access those arrays to do some work on them later. I've gotten this far but can't figure the rest out to make it work....
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
public static void main(String[] args) {
String[][] layer1 = {
{"to1", "TYPE1", "start"},
{"to2", "TYPE1", "start"}
};
String[][] layer2 = {
{"to3", "TYPE2" ,"item1"},
{"to3", "TYPE2" ,"item2"}
};
HashMap<String,Object> hashMap = new HashMap<String,Object>();
hashMap.put("layer1", layer1);
hashMap.put("layer2", layer2);
Iterator<Entry<String, Object>> iterator = hashMap.entrySet().iterator();
while(iterator.hasNext()){
hashMap.values().toArray();
for (???) {
// lets print array here for example
}
}
}
Smells like homework, but a few suggestions -
there's no reason for your Hashmap to be of the form <String,Object> - make it <String, String[][]> , as that's what you're storing.
You're iterating twice. You either
- iterate through the map, either the keys, values or entries. Each item is an iterator return value, e.g.
for (String[][] s:map.values()){
...
}
hashmap.values.toArray gives you all of the contents, which is the same thing your iterator is doing.
if you're only iterating through the contents, then you're not really using a map, as you're never making use of the fact that your values are available by key.
... just mixing too many languages to learn atm
Can I suggest that you need to stop and take the time to learn Java properly. Your code looks like you are trying to write "perlish" ... associative arrays and arrays instead of proper types. The end result is Java code that is slow and fragile compared with code that is designed and written using the Java mindset.
It might seem like you are being productive, but what you are producing is likely to be problematic going forward.
Your while loop should look like -
while(iterator.hasNext()){
String[][] arr = (String[][])iterator.next().getValue();
for (String[] strings : arr) {
for (String string : strings) {
System.out.println(string);
}
}
}
Your code is bad formed here:
while(iterator.hasNext()){
hashMap.values().toArray();
for (???) {
// lets print array here for example
}
}
You try to iterate using the Iterator "iterator" but next you call to
hashMap.values().toArray();
To get the next item of the loop you need to use iterator.next(); to fetch it. Also is good to change the "Object" by String[][] or to List<String[]> or List<List<String>>.
import java.util.HashMap;
import java.util.Map;
import java.util.Iterator;
import java.util.Map.Entry;
public static void main(String[] args) {
String[][] layer1 = {
{"to1", "TYPE1", "start"},
{"to2", "TYPE1", "start"}
};
Map<String,String[][]> map= new HashMap<String,String[][]>();
map.put("layer1", layer1);
Iterator<Entry<String, String[][]>> iterator = map.entrySet().iterator();
while(iterator.hasNext()){
Entry<String, String[][]> entry = iterator.next();
System.out.println("Key:" + entry.getKey());
String[][] value = entry.getValue();
for(int x=0;x<value.length;x++){
for(int y=0;y<value[x].length;y++){
System.out.println("String[" + x + "][" + y + "]:" + value[x][y]);
}
}
}
}
Also you can use "for each" loop to simplify the code insted using the "while":
for (Entry<String, String[][]> entry : map.entrySet()){
System.out.println("Key:" + entry.getKey());
String[][] value = entry.getValue();
for(int x=0;x<value.length;x++){
for(int y=0;y<value[x].length;y++){
System.out.println("String[" + x + "][" + y + "]:" + value[x][y]);
}
}
}
Or if you only need the values:
for (Entry<String, String[][]> entry : map.values()){
String[][] value = entry.getValue();
for(int x=0;x<value.length;x++){
for(int y=0;y<value[x].length;y++){
System.out.println("String[" + x + "][" + y + "]:" + value[x][y]);
}
}
}
Related
I'm having trouble with a homework, the thing is I have around 40.000 HashMap<Character,Character> objects stored in a ArrayList<HashMap<Character,Character>>object.
Each object HashMap<Character,Character> object represent a key for a substitution cipher. So one HashMap object might be: a->a; b->b; c->c; d->d; e->e; f->f; g->h; h->g
which means that the g and h are swapped during encription/decryption.
The problem is that I'm coding a brute force attack on this cipher, so I'm looping over those 40.000 keys.
When the program detects that say g->h It's a wrong substitution, I want to delete all the HashMap objects that contain this entry, not only the current element that I'm working with inside the loop and thus be able to avoid checking the keys one by one.
So far I've tried the following, but its getting stuck no exception or anything just doesnt finish, not even while debugging:
ArrayList<HashMap<Character,Character>> all_keys = new ...`
all_keys = generateAllCombinations();`
ArrayList<HashMap<Character,Character>> keys_to_delete = new ...`
for(HashMap<Character,Character> key:all_keys){`
all_keys.removeAll(keys_to_delete);
\\other stuff going on...`
if (!letters[0].getChar().equals(Constants.CHAR_E)){
Character invChar = key.get(Constants.CHAR_E);
for(HashMap<Character,Character> key2 : all_keys){
if(key2.get(Constants.CHAR_E).equals(invChar)){
keys_to_delete.add(key2);
}
}
}
}
It was lready mentioned that you have to be careful when removing elements from a collection that you are currently iterating over. This may easily cause a ConcurrentModificationException. For "complicated" cases where you can not easily use an iterator, a pattern that can often be applied is that instead of doing something like
Collection<Element> collection = ...
for (Element element : collection)
{
if (hasToBeRemoved(element))
{
// Will cause a ConcurrentModificationException!
collection.remove(element);
}
}
you collect the elements to be removed, and remove them all at once
Collection<Element> collection = ...
Collection<Element> elementsToRemove = new List<Element>();
for (Element element : collection)
{
if (hasToBeRemoved(element))
{
elementsToRemove.add(element);
}
}
collection.removeAll(elementsToRemove);
According to the code, you seem to have tried something similar, with your keys_to_delete, but that's not entirely clear.
And as mentioned in the comment, you should consider dedicated data structures for the substitutions etc. But even if you wish to stick to Lists and Maps for this purpose, you should always use the interface in the declarations. So instead of
ArrayList<HashMap<Character,Character>> allKeys = ...
you should write
List<Map<Character,Character>> allKeys = ...
However, regarding the actual question: It seems like the main issue can be resolved by introducing a method like computeKeysContaining(maps, entry) that returns all maps from a given collection that contain a certain entry.
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class MapListKeyRemoval
{
public static void main(String[] args)
{
List<Map<Character,Character>> allKeys = generateAllCombinations();
print("All keys", allKeys);
Set<Map<Character,Character>> keysToDelete =
new LinkedHashSet<Map<Character,Character>>();
for (Map<Character, Character> key : allKeys)
{
for (Entry<Character, Character> entry : key.entrySet())
{
if (isInvalidMapping(entry))
{
System.out.println("Invalid mapping: "+entry);
Set<Map<Character, Character>> keysWithInvalidMapping =
computeKeysContaining(allKeys, entry);
print("Keys with invalid mapping", keysWithInvalidMapping);
keysToDelete.addAll(keysWithInvalidMapping);
}
}
}
print("Keys to delete", keysToDelete);
allKeys.removeAll(keysToDelete);
print("All keys after removal", allKeys);
}
private static void print(
String message, Iterable<Map<Character,Character>> keys)
{
System.out.println(message);
for (Map<Character, Character> key : keys)
{
System.out.println(key);
}
}
private static Set<Map<Character, Character>> computeKeysContaining(
List<Map<Character,Character>> allKeys,
Entry<Character, Character> entry)
{
Set<Map<Character,Character>> keysContainingEntry =
new LinkedHashSet<Map<Character,Character>>();
for (Map<Character, Character> key : allKeys)
{
Object value = key.get(entry.getKey());
if (value != null && value.equals(entry.getValue()))
{
keysContainingEntry.add(key);
}
}
return keysContainingEntry;
}
private static boolean isInvalidMapping(Entry<Character, Character> entry)
{
return entry.getKey().equals('g') && entry.getValue().equals('h');
}
private static List<Map<Character, Character>> generateAllCombinations()
{
List<Map<Character, Character>> result =
new ArrayList<Map<Character,Character>>();
result.add(createMapping('f','i','r','s','t','-','g','h'));
result.add(createMapping('s','e','c','o','n','d','g','x'));
result.add(createMapping('t','h','i','r','d','-','g','h'));
result.add(createMapping('f','o','u','r','t','h','g','x'));
return result;
}
private static Map<Character, Character> createMapping(char ... c)
{
Map<Character, Character> map =
new LinkedHashMap<Character, Character>();
for (int i=0; i<c.length/2; i++)
{
map.put(c[i*2+0], c[i*2+1]);
}
return map;
}
}
(Apart from that, I wonder why the people who are answering questions are those who (have to) create a https://stackoverflow.com/help/mcve even for such simple questions, but don't want to speculate about the reasons here)
Use Iterator. My Solution is working but may be it requires tuning for performance.
Iterator<Map<String,String>> all_keys_iterator = all_keys.iterator();
List<Map<String,String>> all_keys_new = new ArrayList<Map<String,String>> ();
while(all_keys_iterator.hasNext()) {
Map<String,String> copyMap = new HashMap<String,String> ();
Map<String,String> all_keys_map = all_keys_iterator.next();
for(String key: all_keys_map.keySet()) {
if (!key.equalsIgnoreCase("key1")){
copyMap.put(key, all_keys_map.get(key));
}
}
if(!copyMap.isEmpty()) {
all_keys_iterator.remove();
all_keys_new.add(copyMap);
}
}
all_keys.addAll(all_keys_new);
for(Map<String,String> map: all_keys) {
for(String key: map.keySet()) {
System.out.println("key: " + key + " Value: " + map.get(key));
}
}
I have a program that takes the number of instances of a character in a string and then puts them into a HashMap. I have it working, but how do I alphabetize the HashMap. Here is my code:
import java.util.*;
import java.lang.*;
import javax.swing.JOptionPane;
import java.io.*;
public class CharacterCount
{
public static void main(String args[])
{
{
String s = JOptionPane.showInputDialog("Enter in any text.");
String str = s.replaceAll("[., ]", "");
String[] splitted = str.split("");
HashMap hm = new HashMap();
for (int i = 0; i < splitted.length; i++) {
if (!hm.containsKey(splitted[i])) {
hm.put(splitted[i], 1);
} else {
hm.put(splitted[i], (Integer) hm.get(splitted[i]) + 1);
}
}
for (Object word : hm.keySet()) {
if (word.equals("")) {
System.out.println("Spaces: " + (Integer) hm.get(word));
}
else {
System.out.println(word + ": " + (Integer) hm.get(word));
}
}
}
}
}
What do I need to add to make it alphabetize/reorganize the HashMap?
An HashMap is, by default, unsorted. This because its implementation can't rely on order of elements.
If you need a sorted map then you will have to look into a TreeMap which supplies the same interface as a HashMap but it's inherently sorted on keys according to their natural ordering (or a custom Comparator). Mind that a TreeMap doesn't allow ordering on values, so if you need to sort your data by value then you will have to build your own sorted collection.
This is usually done by taking the Map.Entry<K,V> entrySet() and then build a new SortedSet by following your ordering rules.
Most maps, including HashMap, make no promises about order of contents. Consider SortedMap, or maintaining both a hash map and a sorted list in parallel.
Difference between HashMap, LinkedHashMap and TreeMap
I have this input:
5
it
your
reality
real
our
First line is number of strings comming after. And i should store it this way (pseudocode):
associative_array = [ 2 => ['it'], 3 => ['our'], 4 => ['real', 'your'], 7 => ['reality']]
As you can see the keys of associative array are the length of strings stored in inner array.
So how can i do this in java ? I came from php world, so if you will compare it with php, it will be very well.
MultiMap<Integer, String> m = new MultiHashMap<Integer, String>();
for(String item : originalCollection) {
m.put(item.length(), item);
}
djechlin already posted a better version, but here's a complete standalone example using just JDK classes:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class Main {
public static void main(String[] args) throws Exception{
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String firstLine = reader.readLine();
int numOfRowsToFollow = Integer.parseInt(firstLine);
Map<Integer,Set<String>> stringsByLength = new HashMap<>(numOfRowsToFollow); //worst-case size
for (int i=0; i<numOfRowsToFollow; i++) {
String line = reader.readLine();
int length = line.length();
Set<String> alreadyUnderThatLength = stringsByLength.get(length); //int boxed to Integer
if (alreadyUnderThatLength==null) {
alreadyUnderThatLength = new HashSet<>();
stringsByLength.put(length, alreadyUnderThatLength);
}
alreadyUnderThatLength.add(line);
}
System.out.println("results: "+stringsByLength);
}
}
its output looks like this:
3
bob
bart
brett
results: {4=[bart], 5=[brett], 3=[bob]}
Java doesn't have associative arrays. But it does have Hashmaps, which mostly accomplishes the same goal. In your case, you can have multiple values for any given key. So what you could do is make each entry in the Hashmap an array or a collection of some kind. ArrayList is a likely choice. That is:
Hashmap<Integer,ArrayList<String>> words=new HashMap<Integer,ArrayList<String>>();
I'm not going to go through the code to read your list from a file or whatever, that's a different question. But just to give you the idea of how the structure would work, suppose we could hard-code the list. We could do it something like this:
ArrayList<String> set=new ArrayList<String)();
set.add("it");
words.put(Integer.valueOf(2), set);
set.clear();
set.add("your");
set.add("real");
words.put(Integer.valueOf(4), set);
Etc.
In practice, you probably would regularly be adding words to an existing set. I often do that like this:
void addWord(String word)
{
Integer key=Integer.valueOf(word.length());
ArrayList<String> set=words.get(key);
if (set==null)
{
set=new ArrayList<String>();
words.put(key,set);
}
// either way we now have a set
set.add(word);
}
Side note: I often see programmers end a block like this by putting "set" back into the Hashmap, i.e. "words.put(key,set)" at the end. This is unnecessary: it's already there. When you get "set" from the Hashmap, you're getting a reference, not a copy, so any updates you make are just "there", you don't have to put it back.
Disclaimer: This code is off the top of my head. No warranties expressed or implied. I haven't written any Java in a while so I may have syntax errors or wrong function names. :-)
As your key appears to be small integer, you could use a list of lists. In this case the simplest solution is to use a MultiMap like
Map<Integer, Set<String>> stringByLength = new LinkedHashMap<>();
for(String s: strings) {
Integer len = s.length();
Set<String> set = stringByLength.get(s);
if(set == null)
stringsByLength.put(len, set = new LinkedHashSet<>());
set.add(s);
}
private HashMap<Integer, List<String>> map = new HashMap<Integer, List<String>>();
void addStringToMap(String s) {
int length = s.length();
if (map.get(length) == null) {
map.put(length, new ArrayList<String>());
}
map.get(length).add(s);
}
I have text files within a directory. What i need to do is;
---for each word in all files
---find positional indexes of each word within a file
---find each file that the word has passed
In order to do this;
HashMap<String, HashMap<Integer, ArrayList<Integer>>>
I want to use a structure as above.
String word;
String pattern = "[[^\\w\\süÜıİöÖşŞğĞçÇ]\\d]+";
while ((word = infile.readLine()) != null) {
String[] wordList = word.replaceAll(pattern, " ").split("\\s+");
for (int j = 0; j < wordList.length; j++) {
if(!wordList[j].isEmpty()){
if(!refinedDict.containsKey(wordList[j])){
refinedDict.put(wordList[j], 1);
}
else{
refinedDict.put(wordList[j], refinedDict.get(wordList[j])+1);
}
}//end of for
}//end if
else{
//do something
}
}//end for
}//end while
Set<String> keys=refinedDict.keySet();
List<String> list=sortList(keys);
Iterator<String> it=list.iterator();
while(it.hasNext()){
String key=it.next();
outfile.write(key + "\t" + refinedDict.get(key) + "\n");
How can i use the ArrayList in HashMap in a HashMap
EDIT
After applying toto2's solution implementation works. However, in order to write it to a file as ---> word[fileId{positions}, fileId{positions}...]
What can be done? Implementing serializable is not useful for such a design.
I define two new classes FileId and PositionInFile instead of Integers for clarity.
Map<String, Map<FileId, List<PositionInFile>>> wordsWithLocations;
for (int j = 0; j < wordList.length; j++) {
if (!wordList[j].isEmpty()){
if (!wordsWithLocations.containsKey(wordList[j])) {
Map<FileId, List<PositionInFile>> map = new HashMap<>();
List<PositionInFile> list = new ArrayList<>();
list.add(wordPosition[j]);
map.put(fileId, list);
wordsWithLocations.put(wordList[j], map);
} else {
Map<FileId, List<PositionInFile>> map =
wordsWithLocation.get(wordList[j]);
if (map.contains(fileId)) {
map.get(fileId).add(wordPosition[j]);
} else {
List<PositionInFile> list = new ArrayList<>();
list.add(wordPosition[j]);
map.put(fileId, list);
}
}
}
}
...
for (String word : wordsWithLocation) {
int nAppearances = 0;
for (List<PositionInFile> positions :
wordsWithLocation.get(word).values()) {
nAppearances += positions.size();
}
System.out.println(word + " appears " + nAppearances + " times.");
}
However I think it would be simpler and cleaner to define:
public class WordLocation {
FileId fileId;
PositionInFile position;
...
}
and then just have a Map<String, List<WordLocation>>. The downside is that you don't have such an explicit mapping to the files. The information is still there however, and the List<WordLocation> should even have the locations listed in the same order as the files were processed.
Not sure exactly.
But here's a general way that I use for a Map that the value is of Collection type.
Map<String, Collection<something>> map ...
for ... do some job
if map.containsKey(keyFound) {
map.get(foundKey).add(foundValue);
} else {
Collection <- create collection
Collection.add(foundValue);
map.put(foundKey, collection)
}
You can also check Google Guava multi-maps.
Hope that helps...
nested Map would work. however I would create a class for that, i.e.
class WordsInFile{
String fileName;
Map<String, List<Integer>> wordIdxMap;
}
this does actually no big difference with nesting maps. but more readable, and you can add methods like findWord(...)... to avoid to be get lost by invoking twice of maps' get(object) methods. It let you know what you are about to get.
i don't know if it is a good idea...
Assuming you have your HashMap defined as above and add an entry like this:
HashMap<String, HashMap<Integer, ArrayList<Integer>>> outer = ...
HashMap<Integer, ArrayList<Integer>> inner = ...
inner.put(1, new ArrayList<Integer>());
outer.put("key1", inner);
you can retrieve the ArrayList as:
ArrayList<Integer> arr = outer.get("key1").get(1);
I am piping in a file. I am tracking word pairs from the file. Using a treemap the keys are all sorted. However, when i add words to those keys they are not sorted.
here is the part i need help on in the process function:
private static void process(){
if(!result.containsKey(thisWord)){
result.put(thisWord, new ArrayList<String>());
}
// Add nextWord to the list of adjacent words to thisWord:
result.get(thisWord).add(nextWord); // nextword is not sorted within the key
thisword is sorted
nextWord is not..
Can i use Collections.sort(result); somehow?
im just not sure how i get to the nextWord within the result to do that.
or, is there no way to do it within my situation. I would rather not change things unless you recommend it.
This is the program
import java.util.Map.Entry;
import java.util.TreeSet;
import java.io.*;
import java.util.*;
public class program1 {
private static List<String> inputWords = new ArrayList<String>();
private static Map<String, List<String>> result = new TreeMap<String, List<String>>();
public static void main(String[] args) {
collectInput();
process();
generateOutput();
}
private static void collectInput(){
Scanner sc = new Scanner(System.in);
String word;
while (sc.hasNext()) { // is there another word?
word = sc.next(); // get next word
if (word.equals("---"))
{
break;
}
inputWords.add(word);
}
}
private static void process(){
// Iterate through every word in our input list
for(int i = 0; i < inputWords.size() - 1; i++){
// Create references to this word and next word:
String thisWord = inputWords.get(i);
String nextWord = inputWords.get(i+1);
// If this word is not in the result Map yet,
// then add it and create a new empy list for it.
if(!result.containsKey(thisWord)){
result.put(thisWord, new ArrayList<String>());
}
// Add nextWord to the list of adjacent words to thisWord:
result.get(thisWord).add(nextWord); // need to sort nextword
// Collections.sort(result);
}
}
private static void generateOutput()
{
for(Entry e : result.entrySet()){
System.out.println(e.getKey() + ":");
// Count the number of unique instances in the list:
Map<String, Integer> count = new HashMap<String, Integer>();
List<String> words = (List)e.getValue();
for(String s : words){
if(!count.containsKey(s)){
count.put(s, 1);
}
else{
count.put(s, count.get(s) + 1);
}
}
// Print the occurances of following symbols:
for(Entry f : count.entrySet()){
System.out.println(" " + f.getKey() + ", " + f.getValue() );
}
}
System.out.println();
}
}
If you want the collection of "nextword"s sorted, why not use a TreeSet rather than an ArrayList? The only reason I can see against it is if you might have duplicates. If duplicates are allowed, then yes, use Collections.sort on the ArrayList when you're done adding to them. Or look in the Apache Commons or Google collection classes - I don't know them off the top of my head, but I'm sure there is a sorted List that allows duplicates in one or both of them.
result.get(thisWord).add(nextWord);
Collections.sort(result.get(thisWord));
Y Don't you try some thing like this
Collections.sort(inputWords);