I am trying to build a many to one key value pair in java. Till now all I have manged is this
public class KeyStore {
int i=1;
Map<Integer,String> map1=new HashMap<Integer,String>();
Map<String,List<Integer>> map2=new HashMap<String,List<Integer>>();
public synchronized int put(String blobString) {
if(map1.containsValue(blobString)){
int r=blobString.hashCode()+i*blobString.hashCode();
i++;
map1.put(r, blobString);
List<Integer> j=map2.get(blobString);
List<Integer> k=j;
map2.remove(blobString);
k.add(r);
map2.put(blobString, k);
return r;
}
else{
map1.put(blobString.hashCode(),blobString);
List<Integer> x=new ArrayList<Integer>();
x.add(blobString.hashCode());
map2.put(blobString,x);
return blobString.hashCode();
}
}
public synchronized String get(int objectId) {
return map1.get(objectId);
}
What this does is if i put
ks.put("abc")
ks.put("abc")
Here ks is an instant of the class containing the above methods.
it results in
{1916062554=abc, 958031277=abc}
But what I want is
191602554,958031277=abc
and if i use get() on either of these keys it should output the value abc. Also delete() should delete the most recent key and not harm the other keys.
I thought of using
Map<ArrayList<Integer>,String> keystore=new HashMap<ArrayListInteger>,String>();
but I dont know how to implement the put method i.e how to insert a key in a map of lists. Need help with this.
EDIT 1
I am able to make the get and put methods work. Struggling with the delete method. Wrote it some what like this
Map<Integer,String> map1=new HashMap<Integer,String>();
Map<String,List<Integer>> map2=new HashMap<String,List<Integer>>();
public synchronized void delete(int objectId) {
map1.remove(objectId);
Iterator<Entry<String, List<Integer>>> it = map2.entrySet().iterator();
loop1: while (it.hasNext()) {
#SuppressWarnings("rawtypes")
Map.Entry pairs = (Map.Entry)it.next();
#SuppressWarnings("unchecked")
List<Integer> z=(List<Integer>) pairs.getValue();
if(z.contains(objectId)){
//System.out.println(z.size());
String key=(String) pairs.getKey();
System.out.println(z+" "+key);
if(z.size()==1){
map2.remove(key);
break loop1;
}
else{
z.remove(objectId);
map2.remove(key);
map2.put(key, z);
break loop1;
}
}
}
}
Basically map1 contains the mappings
123=>abc,456=>abc
and map2 contains
abc=>[123,456]
I am getting an arrayindexoutofbound exception. What I am trying in the delete method is to iterate across each blob String and then check in the list of values associated with the blobstring whetehr the required objectID is present. if it is then I remove that object id from the list and append the new mapping. Any help?
EDIT 2
The updated and working get and put methods are given above.
The Map JavaDoc says:
A map cannot contain duplicate keys; each key can map to at most one value.
But you can get around this by making the value a list of strings:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
<P>{#code java MultiValueHashMap}</P>
**/
public class MultiValueHashMap {
public static final void main(String[] ignored) {
Map<Integer,List<String>> mapOfIntStrs = new HashMap<Integer,List<String>>();
//Add elements
addStringToMap(mapOfIntStrs, 1, "one");
addStringToMap(mapOfIntStrs, 1, "two");
addStringToMap(mapOfIntStrs, 1, "three");
addStringToMap(mapOfIntStrs, 2, "four");
addStringToMap(mapOfIntStrs, 2, "five");
//Output
Set<Integer> keyNumSet = mapOfIntStrs.keySet();
Iterator<Integer> keyNumItr = keyNumSet.iterator();
while(keyNumItr.hasNext()) {
Integer keyNum = keyNumItr.next();
List<String> strList = mapOfIntStrs.get(keyNum);
System.out.println(keyNum);
for(String s : strList) {
System.out.println(" " + s);
}
}
}
private static final void addStringToMap(Map<Integer,List<String>> mapTo_addTo, int keyNum, String value) {
if(mapTo_addTo.containsKey(keyNum)) {
mapTo_addTo.get(keyNum).add(value);
} else {
List<String> strList = new ArrayList<String>();
strList.add(value);
mapTo_addTo.put(keyNum, strList);
}
}
}
Output:
[C:\java_code\]java MultiValueHashMap
1
one
two
three
2
four
five
Regarding multiple keys per value, you could certainly do this, although I'm not sure it's recommended. According to the HashMap API:
The HashMap class is roughly equivalent to Hashtable, except that it is unsynchronized and permits nulls.
And the Hashtable API:
To successfully store and retrieve objects from a hashtable, the objects used as keys must implement the hashCode method and the equals method.
So while this would work with ArrayList<Integer> keys, for anything with customized keys, containing non-standard classes, unless you are correctly implementing hashCode() for those objects, the HashMap may not function properly.
It seems like you need a couple of data structures as fields in your class:
stringMap: Map<Integer,String>
{1916062554=abc, 958031277=abc}, etc.
because for get you want to look up items by key
keys: Map<String,List<Integer>>
{ "abc" = {1916062554, 958031277}
because for delete you want to know the keys for a given item, in order.
To add to the Map:
public void put(String item) {
List<Integer> list = getOrCreateList(item,keys);
int key = calculateKey(item,list);
list.add(key);
stringMap.put(key,item);
}
private static List<Integer> getOrCreateList(String item, Map<String,List<Integer>> map) {
List<Integer> list = map.get(item);
if(list == null) {
list = new ArrayList<Integer>();
map.put(item,list);
}
return list;
}
To get from the map is easy:
public String get(int key) {
return stringMap.get(key);
}
To delete from the map -- if I understand your requirements correctly -- you need to find the most recent key in the list corresponding to the key provided...
public void delete(int key) {
String item = stringMap.get(key);
if(item == null) {
// ... deal with
}
List<Integer> keys = keys.get(item);
// lazily using methods which don't exist in the Java API
// but which illustrate the point.
keys.removeLast();
if(keys.isEmpty()) {
stringMap.remove(key);
list.remove(item);
}
}
Related
I have a List<Brand> categories; with 1000+ items.
For each item from the list I have id, to get that I use categories.getId();
And I have an array int[] sortedIdArr = {4,53,102,403,110,5,6,8,12};
I would like to sort my categories list and make order by id how it is in sortedIdArr.
How can I implement that ?
private void sortBrandsById(List<Brand> categories) {
Collections.sort(categories, new Comparator<Brand>() {
public int compare(Brand o1, Brand o2) {
}
});
}
Can I use Collections.sort ?
Typically you would use Collections.sort, or the equivalent idioms in Java 8 if applicable, or a sorted Collection such as TreeSet.
However in this case you want to follow a pre-defined order, dictated by your sortedIdArr array.
One way to achieve that is to use a linked collection (e.g. a LinkedHashSet).
Then you iterate your sortedIdArr array, and search your List<Brand> for an object with the given ID.
If found, you add the Brand object with the given ID to your LinkedHashSet, which will retain the insertion order.
Note that if an ID is not found, your Set will not exactly "match" the array.
Self-enclosed example, using Java 8
package test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
public class Main {
// simplified Brand pojo
static class Brand {
int id;
public Brand(int id) {
this.id = id;
}
public int getId() {
return id;
}
// for output clarity
#Override
public String toString() {
return String.format("Brand: %d", id);
}
}
public static void main(String[] args) throws Exception {
// simplified ID list
int[] sortedIdArr = {4,53,102};
// "randomly" ordered Brand list
final List<Brand> categories = new ArrayList<Brand>() {
{
add(new Brand(1));
add(new Brand(102));
add(new Brand(53));
add(new Brand(4));
add(new Brand(0));
}
};
// destination: linked set
Set<Brand> linked = new LinkedHashSet<Brand>();
// streaming the ID array in order
Arrays.stream(sortedIdArr)
.forEach((i) -> {
// retrieving a Brand with same ID as the current
// from the "randomly" ordered list
Optional<Brand> toAdd = categories.stream()
.filter((b) -> b.getId() == i)
.findFirst();
// making sure there's one
if (toAdd.isPresent()) {
// adding to linked set
linked.add(toAdd.get());
}
}
);
System.out.println(linked);
}
}
Output
[Brand: 4, Brand: 53, Brand: 102]
Imperative idiom for older Java versions
for (int i: sortedIdArr) {
for (Brand b: categories) {
// assuming no nulls
if (b.getId() == i) {
linked.add(b);
break;
}
}
}
Yes you can use the Collections.sort()
To sort your Brand using id :
public int compare(Brand o1, Brand o2) {
return o1.getId().compareTo(o2.getId());
}
To sort your Brand using the array of id sortedIdArr :
Implement the Comparator Class :
class C implements Comparator<A> {
int[] idOrder;
public C(int[] idOrder) {
super();
this.idOrder = idOrder;
}
#Override
public int compare(A o1, A o2) {
Integer indexofO1 = Arrays.binarySearch(idOrder, o1.getId());
Integer indexofO2 = Arrays.binarySearch(idOrder, o2.getId());
return indexofO1.compareTo(indexofO2);
}
}
The key idea here is to inverse the process and compare using the index of the id instead of the id itself !
To use it :
Collections.sort(list, new C (idOrder));
Test Example :
int[] idOrder = new int [] {3,1,2};
List<A> list = new ArrayList<>();
list.add(new A(1));
list.add(new A(2));
list.add(new A(3));
System.out.println(list);
//Output : [A [id=1], A [id=2], A [id=3]]
Collections.sort(list, new C(idOrder));
System.out.println(list);
//Output : [A [id=3], A [id=1], A [id=2]]
You can do it with Collections.sort(...) but I strongly recommend not to go for Comparator method in this situation with this number of items in your list.
You can have a loop on your List<Brand> categories and add them in a HashMap<Integer,Brand> named tempMap. Then use it for lookup them in the order of your sortedIdArr array. Change your sort method like this:
private void sortBrandsById(List<Brand> categories, int [] sortedIdArr) {
HashMap<Integer,Brand> tempMap = new HashMap<Integer, Brand>(categories.size());
for (int i = 0; i < categories.size(); i++) {
tempMap.put(categories.get(i).getId(), categories.get(i));
}
categories = new ArrayList<Brand>(sortedIdArr.length);
for (int i = 0; i < sortedIdArr.length; i++) {
categories.add(tempMap.get(sortedIdArr[i]));
}
}
This way of sorting is from order O(n) for creating the tempMap + O(n) for recreating the category list. Although, the O(1) is not guaranteed for HashMap's get/put operations, java's decent hashing implementation very good and reliable. So the total complexity can not be very greater than O(n). At least it is very better than O(n^2). Time complexity is very important and I don't think you can find a way better than something very near O(n) complexity.
Hope this would be helpful.
You can use the following code(You need the Apache commons lang jar-otherwise you have to iterate through your array to find the index).
private static void sortBrandsById(List<Brand> categories,int[] array) {
Collections.sort(categories, new Comparator<Brand>() {
public int compare(Brand o1, Brand o2) {
return ArrayUtils.indexOf(array,o1.getId())-ArrayUtils.indexOf(array,o2.getId());
}
});
}
If you are able to put your predefined sorting order in a list not in an array , it will be much easier.
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 would need to sort a list of words based on its frequency.
My input:
Haha, hehe, haha, haha, hehe, hehe.... , Test
For example in my data structure I would have
Haha:3
Hehe:5
Test:10
I would need the data structure to be sorted at the output in this manner:
Test:10
Hehe:5
Haha:3
Such that if I pop the top of the data structure I would be able to obtain the element and its corresponding frequency.
The number of elements is unknown initially and hence, an array would not be feasible. If I would like to obtain the top few elements I would just need to access it sequentially. Is this possible in Java?
First, want to confirm:
Can you get all the whole words before sorting? Or these words come continuously in a stream?
(1)For the former case, you can use a Set to store the words, then put them into a PriorityQueue. If you implement the comparator function, the queue will sort the words automatically. I create a new class Pair to store the text and frequency, see the code:
import java.util.Queue;
import java.util.PriorityQueue;
import java.util.Set;
import java.util.HashSet;
import java.util.Comparator;
public class PriorityQueueTest {
public static class Pair {
private String text;
private int frequency;
#Override
public int hashCode() {
return text.hashCode();
}
#Override
public String toString() {
return text + ":" + frequency;
}
public Pair(String text, int frequency) {
super();
this.text = text;
this.frequency = frequency;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public int getFrequency() {
return frequency;
}
public void setFrequency(int frequency) {
this.frequency = frequency;
}
}
public static Comparator<Pair> idComparator = new Comparator<Pair>(){
#Override
public int compare(Pair o1, Pair o2) {
if(o1.getFrequency() > o2.getFrequency()) {
return -1;
}
else if(o1.getFrequency() < o2.getFrequency()){
return 1;
}
else {
return 0;
}
}
};
public static void main(String[] args) {
Set<Pair> data = new HashSet<Pair>();
data.add(new Pair("haha", 3));
data.add(new Pair("Hehe", 5));
data.add(new Pair("Test", 10));
Queue<Pair> queue = new PriorityQueue(16, idComparator);
for(Pair pair : data) {
queue.add(pair);
}
// Test the order
Pair temp = null;
while((temp = queue.poll()) != null) {
System.out.println(temp);
}
}
}
(2)For the other case(the words come continuously), you may use a TreeMap to keep the order.
See ref: http://www.java-samples.com/showtutorial.php?tutorialid=370
To keep the information you need, you could create a class that holds your string and the count (e.g. Pair) and keep the instances of this class in a List<Pair>. This approach would make the increment of the count for a given string inefficient since you would have to look for the element that holds the string in linear time (O(N)) and then increment it.
A better approach is to use a Map<String, Integer>, that way the search is done in constant time (O(1)) and then you can sort the elements in the Set<Map.Entry<String, Integer>> returned by Map.entrySet().
List item
I am starting with the URL below as reference and I will be building on that reference:
How can I count the occurrences of a list item in Python?
Now, the building starts:
>>> from collections import Counter
>>> word_list = ['blue', 'red', 'blue', 'yellow', 'blue', 'red','white','white']
>>> Counter(word_list)
Counter({'blue': 3, 'red': 2, 'white': 2, 'yellow': 1})
Note how Counter(word_list) displays the list of elements i.e. word/frequency pairs sorted in order of decreasing frequency for you. Unfortunately, extracting the words and compiling them in a list sorted in the same order takes a little more work:
(1) Get "size" as the number of elements in the JSON object.
(2) Apply the "most_common" method on the JSON object to get a sorted array of the elements by frequency.
(3) Apply a list comprehension to generate the list of the words extracted from the sorted array.
>>> size = len(Counter(word_list))
4
>>> word_frequency_pairs = Counter(word_list).most_common(size)
>>> word_frequency_pairs
[('blue', 3), ('white', 2), ('red', 2), ('yellow', 1)]
>>> [i[0] for i in word_frequency_pairs]
['blue', 'white', 'red', 'yellow']
There is a reason why I love Python :)
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
How to remove duplicate elements in an array using HashMap without using hashset in java...Below code describes removal of duplicates in array..
Now i need to write using hashmap for generating key and value pairs
import java.util.*;
class TestArray{
public static void main(String arg[])
{
ArrayList<String> wordDulicate = new ArrayList<String>();
wordDulicate.add("chennai");
wordDulicate.add("bangalore");
wordDulicate.add("hyderabad");
wordDulicate.add("delhi");
wordDulicate.add("bangalore");
wordDulicate.add("mumbai");
wordDulicate.add("mumbai");
wordDulicate.add("goa");
wordDulicate.add("calcutta");
wordDulicate.add("hyderabad");
ArrayList<String> nonDupList = new ArrayList<String>();
Iterator<String> dupIter = wordDulicate.iterator();
while(dupIter.hasNext())
{
String dupWord = dupIter.next();
if(nonDupList.contains(dupWord))
{
dupIter.remove();
}else
{
nonDupList.add(dupWord);
}
}
System.out.println(nonDupList);
}
}
A HashSet is implemented in terms of a HashMap anyway. If you specifically want to use a HashMap, use it the same way as HashSet does: use a dummy constant new Object() as the map value everywhere.
Well a HashMap will prevent you from entering duplicate keys, the same way as HashSet. Actually, many implementations of HashSet just use a HashMap under the hood.
So you can do:
HashMap<String, String> map = new HashMap<String, String>();
for (String s : WordDuplicate)
map.put( s, s );
Now you can access the key/values just like a HashMap.
import java.util.HashSet;
import java.util.Stack;
public class stackdupes {
public static void main(String[] args) {
Stack<Integer> st = new Stack<Integer>();
int[] arr= {1,2,3,3,4,5,5,7};
HashSet<Integer> set = new HashSet<Integer>();
for (int i=0;i<arr.length;i++) {
if(set.add(arr[i]) == true)
st.push(arr[i]);
}
System.out.println(st);
}
}