remove similar (redundant) strings from Arraylist - java

I'm trying to remove similar strings from an ArrayList but I'm getting this error:
CurrentModificationException
and here is my method where I pass my original arrayList (old) and get a new list without redundant strings.
ArrayList<String> removeRed(ArrayList<String> old) throws IOException
{
ArrayList<String> newList = new ArrayList<String>();
for (int i=0; i< old.size(); i++)
{
if(newList.size() < 1)
{
newList.add(old.get(0));
} else{
for(Iterator<String> iterator = newList.iterator(); iterator.hasNext();) {
while(iterator.hasNext())
{
if(!ChopMD((String) iterator.next()).equals(ChopMD(old.get(i))))
{
newList.add(old.get(i));
Log.e("new algo", "" + old.get(i) );
}
}
}
}
}}
Note that my ChopMD() returns a particular string and it works fine.
It works fine for the first few strings, this it throws that exception. Any suggestion to resolve this issue would be appreciated it. Thanks.

If you have no problems with using the standard library (always preferable, why reinvent the wheel) try
List<String> uniques = new ArrayList<String>(new HashSet<String>(oldList));
The HashSet will only contain unique strings and the ArrayList constructor takes any Collection (including a HashSet) to build a list from.
Judging from your comments it seems like you are trying to implement an Associative Array with unique keys using an ArrayList. The better approach is to use a Map implementation like HashMap to pair IDs with their associated Strings.
Map<Integer, String> map = new HashMap<>();
map.put(1, "This string corresponds to ID=1");
map.put(3, "Donald Ducks Nephews");
map.put(7, "Is a Prime");
Then to get a value associated with an ID:
int key = someObject.getID();
String value = map.get(key);
All the Map implementations use unique keys so there is no need for you to check for redundant IDs, if you try to add a new (key,value) pair the value associated with the ID will be replaced if the map contains the key.
map.put(1, "New String");
String s = map.get(1); //s will no longer be "This string corresponds to ID=1"
If you don't want this behavior you have the choice of either subclassing one of the Map implementations to ignore .put(key, value) if the map contains key,value or delegating .put(key,value) to some other class.
Subclassing:
public class UniqueValueHashMap<K,V> extends HashMap<K, V>{
#Override
public V put(K key, V value) {
if (containsKey(key))
return null;
return super.put(key, value);
}
Delegating
public class SomeClass {
private Map<Integer, String> map = new HashMap<>();
// ...stuff this class does
public String put(int key, String value) {
if (map.containsKey(key))
return null;
return map.put(key, value);
}
// ...more stuff this class does
}
Delegation is the better approach, notice how you can change the map implementation (using maybe a TreeMap instead of HashMap) without introducing a new class where you override the .put(key,value) of TreeMap.

You can iterate much easier by this
for (String oldString : old){
for (String newString : newList){
}
}
Also you can use Set to have unique strings
Set<String> newList = new HashSet<String>();
Your error is because you are changing the list WHILE it is still iterated.

Related

Java HashMap key fits to a pattern?

I have a Map dataset, and I want to iterate through the keys and search for matches.
So I want to find the maps element, where the key fits to this pattern:
String searchedKey = "A?C"; // ? means it can be any character
Map<String, MyObject> myMap = new HashMap<>();
myMap.put("ABC", MyObject(1));
myMap.put("CDF", MyObject(2));
myMap.put("ADS", MyObject(3));
for (Map.Entry<String,MyObject> entry : myMap.entrySet()) {
// in this case, I want to find the first element, because it's key fits the searchedKey, where ? can be anything
}
How can I do this?
Thanks!
You could do something like this to return a list of found MyObjects. Note I changed ? to . for any character.
String searchedKey = "A.C"; // ? means it can be any character
Map<String, MyObject> myMap = new HashMap<>();
myMap.put("ABC", new MyObject(1));
myMap.put("CDF", new MyObject(2));
myMap.put("ARS", new MyObject(3));
myMap.put("VS", new MyObject(4));
myMap.put("AQC", new MyObject(3));
myMap.put("DS", new MyObject(3));
myMap.put("ASC", new MyObject(10));
List<Map.Entry<String,MyObject>> list = myMap.entrySet().stream()
.filter(e -> e.getKey().matches(searchedKey))
.collect(Collectors.toList());
list.forEach(System.out::println);
Prints
ASC=10
ABC=1
AQC=3
The MyObject class
class MyObject {
int val;
public MyObject(int v) {
this.val = v;
}
public String toString() {
return val + "";
}
}
You could use Regex-Patterns that allow to search Strings for matchings of a logical sequence using String#matches(String).
Here is a page that might help you create and test a regex for your needs. You might also have to construct your pattern flexible during runtime, depending on how your search works.
Tho keep in mind that a HashMap does not keep the order in which the keys were inserted. keySet() does not return them in a fixed order. If you need them ordered, you could use a LinkedHashMap

add elements in arraylist inside hashmap

I am trying to build a dynamic hashmap of type String and arraylist dynamically. I have some json data coming from server and instead of declaring many arraylist I want to save them in hashmap with String as key and arraylist as value.
Here is what I am doing now
ArrayList<classproperty> allStu;
ArrayList<classproperty> allEmp;
HashMap<String, ArrayList<classproperty>> hash;
if (type.equals("Student")) {
prop = new classproperty("Student", info.getJSONObject(i).getJSONObject("student").getJSONArray("class").getJSONObject(s).getJSONObject("type").getString("name"));
allStu.add(prop);
}
if (type.equals("Emp")) {
prop = new esSignalProperty("Emp", info.getJSONObject(m).getJSONObject("emp").getJSONObject(s).getJSONObject("dept").getString("name"));
allemp.add(prop);
}
hash.put("Student", allStu);
hash.put("Emp", allemp);
So it is ugly way to do it...and I would like to do it by directly putting into hashmap without declaring so many arraylist. please ignore json string extraction as it is just dummy.
You just need to initialize the arraylist in the beginning and then just add value based on key. if you know the keys that I guess you know you can do like this
public HashMap<String, ArrayList<classproperty>> hash
hash.put("Student", new ArrayList<classproperty>());
hash.put("Emp", new ArrayList<classproperty>());
after just as #steffen mention but with minor change
hash.get("Student").add(prop);
hash.get("Emp").add(prop);
It is nothing very different from what other purposed but may be still can help.
hash.get("Student").put(prop)
could be a solution, as you know the key inside the map.
Using this way you can leave out the 'allStu' and 'allEmp' Lists, as you can get them directly from the map.
I would suggest using MultiMap from Guava library that already supports this. If you don't plan to import this library, then you can roll your own manually as a wrapper of a Map<K, List<V>>:
//basic skeleton of the multimap
//as a wrapper of a map
//you can define more methods as you want/need
public class MyMultiMap<K,V> {
Map<K, List<V>> map;
public MyMultiMap() {
map = new HashMap<K, List<V>>();
}
//in case client needs to use another kind of Map for implementation
//e.g. ConcurrentHashMap
public MyMultiMap(Map<K, List<V>> map) {
this.map = map;
}
public void put(K key, V value) {
List<V> values = map.get(key);
if (values == null) {
//ensure that there will always be a List
//for any key/value to be inserted
values = new ArrayList<V>();
map.put(key, values);
}
values.add(value);
}
public List<V> get(K key) {
return map.get(key);
}
#Override
public String toString() {
//naive toString implementation
return map.toString();
}
}
Then just use your multimap:
MyMultiMap myMultiMap = new MyMultiMap<String, ClassProperty>();
myMultiMap.put("student", new ClassProperty(...));
myMultiMap.put("student", new ClassProperty(...));
System.out.println(myMultiMap);

How to sort " ArrayList<HashMap<String, String>> arrList " alphabatically?

Can you guide me how can I sort Array List having Hash Map alphabatically?
JSONArray jArr2 = new JSONArray(jsonString2);
for(int i=0;i<jArr2.length();i++){
HashMap<String, String> map = new HashMap<String, String>();
map.put("titleName",jArr2.getJSONObject(i).getString("titleName"))
programList.add(map);
}
Implement a Comparator<HashMap<String, String>> which just extracts the value assocated with the value key, then use Collections.sort method to sort your arraylist.
For e.g.:
class MyComparator implements Comparator<Map<String, String>>{
private final String key;
public MyComparator(String key)
{
this.key = key;
}
public int compare(Map<String, String> first,
Map<String, String> second)
{
// TODO: Null checking, both for maps and values
String firstValue = first.get(key);
String secondValue = second.get(key);
return firstValue.compareTo(secondValue);
}
}
Looking at your example, I don't think you need a Map to be involved at all. What you have is a list of Maps, where every Map only has one key, which is "titleName". Why not just have a list of titlenames? Then your code would look like this:
JSONArray jArr2 = new JSONArray(jsonString2);
List<String> titleNames = new ArrayList<>();
for (int i = 0; i < jArr2.length(); i++) {
titleNames.add(jArr2.getJSONObject(i).getString("titleName"))
}
You know that the list only contains titleNames, you don't need to complicate the data structure with Maps!
Then you can sort the list simply by using
Collections.sort(titleNames);
Note that this will work while the other answers that suggests Collections.sort() on the list of maps will not work. This is because titleNamees is a List of Strings, which implement Comparable (ie the sort() method knows how to order them with respect to each other), while Map does not implement comparable (as there are multiple ways to order Maps - number of entries, total number of bytes, etc).
Yes you can use Collections.sort(); with a custom comparator. Here is the doc.
Collections.sort(YOUR_ARRAY_LIST, new YourCustomComparator());
And this should be the class you must have
class YourCustomComparator implements Comparator<HashMap<String, String>> {
#Override
public int compare(HashMap<String, String> lhs, HashMap<String, String> rhs) {
// check here your objects. lhs and rhs. compare them as you want
// return 1 if lhs is greater than rhs
// return 0 if ther are same
// return -1 otherwise
}
}

How to have a key with multiple values in a map?

I have a map like this
Map map=new HashMap();//HashMap key random order.
map.put("a",10);
map.put("a",20);
map.put("a",30);
map.put("b",10);
System.out.println("There are "+map.size()+" elements in the map.");
System.out.println("Content of Map are...");
Set s=map.entrySet();
Iterator itr=s.iterator();
while(itr.hasNext())
{
Map.Entry m=(Map.Entry)itr.next();
System.out.println(m.getKey()+"\t"+m.getValue()+"\t"+ m.hashCode());
}
Output of the above program is
There are 2 elements in the map.
Content of Map are...
b 10 104
a 30 127
Now I want that key a should have multiple values like
a 10
a 20
a 30
So that I should get all the values associated by a. Please advise how can I achieve that same thing. By nesting of collections, I want key 'a' to have all the three values.
Have you checked out Guava Multimaps ?
A collection similar to a Map, but which may associate multiple values
with a single key. If you call put(K, V) twice, with the same key but
different values, the multimap contains mappings from the key to both
values.
If you really want to use standard collections (as suggested below), you'll have to store a collection per key e.g.
map = new HashMap<String, Collection<Integer>>();
Note that the first time you enter a new key, you'll have to create the new collection (List, Set etc.) before adding the first value.
To implement what you want using the Java standard library, I would use a map like this:
Map<String, Collection<Integer>> multiValueMap = new HashMap<String, Collection<Integer>>();
Then you can add values:
multiValueMap.put("a", new ArrayList<Integer>());
multiValueMap.get("a").add(new Integer(10));
multiValueMap.get("a").add(new Integer(20));
multiValueMap.get("a").add(new Integer(30));
If this results uncomfortable for you, consider wrapping this behaviour in a dedicated Class, or using a third-party solution, as others have suggested here (Guava Multimap).
You shouldn't ignore the generic parameters. What you have is
Map<String, Integer> map = new HashMap<>();
if you want to code the solution yourself, you need
Map<String, List<Integer>> map = new HashMap<>();
Anyhow, the preffered way is to use a Guava Multimap
Put an ArrayList instance in the value part.
void addValue(Map map, Object key, Object value) {
Object obj = map.get(key);
List list;
if (obj == null) {
list = new ArrayList<Object>();
} else {
list = ((ArrayList) obj);
}
list.add(value);
map.put(key, list);
}
For More Info check this.
Use Map with value type as list of values..For example, in your map, while adding an entry, you will put key as "a" and you will have to add it's value as a list of Integer , having all the required values, like 1,2,3,4.
For a Map with entries with same key, has no sense to use get() .But as long as you use iterator() or entrySet() this should work:
class HashMap<String, String> {
Set<Entry<String, String>> entries;
#Override
public Set<Entry<String, String>> entrySet() {
return entries;
}
#Override
public int size() {
return entries.size();
}
public String put(String key, String value) {
if (entries == null) {
entries = new AbstractSet<Entry<String, String>>() {
ArrayList<Entry<String, String>> list = new ArrayList<>();
#Override
public Iterator<Entry<String, String>> iterator() {
return list.iterator();
}
#Override
public int size() {
return list.size();
}
#Override
public boolean add(Entry<String, String> stringStringEntry) {
return list.add(stringStringEntry);
}
};
}
StatusHandler.MyEntry entry = new StatusHandler.MyEntry();
entry.setKey(key);
entry.setValue(value);
entries.add(entry);
return value;
}
};
TL;DR So, what is it useful for? That comes from a hack to redmine-java-api to accept complex queries based on form params:
https://stackoverflow.com/a/18358659/848072
https://github.com/albfan/RedmineJavaCLI/commit/2bc51901f2f8252525a2d2258593082979ba7122

Java HashMap: How to get a key and value by index?

I am trying to use a HashMap to map a unique string to a string ArrayList like this:
HashMap<String, ArrayList<String>>
Basically, I want to be able to access the keys by number, not by using the key's name. And I want to be able to access said key's value, to iterate over it. I'm imagining something like this:
for(all keys in my hashmap) {
for(int i=0; i < myhashmap.currentKey.getValue.size(); i++) {
// do things with the hashmaps elements
}
}
Is there an easy way to do this?
Here is the general solution if you really only want the first key's value
Object firstKey = myHashMap.keySet().toArray()[0];
Object valueForFirstKey = myHashMap.get(firstKey);
You can iterate over keys by calling map.keySet(), or iterate over the entries by calling map.entrySet(). Iterating over entries will probably be faster.
for (Map.Entry<String, List<String>> entry : map.entrySet()) {
List<String> list = entry.getValue();
// Do things with the list
}
If you want to ensure that you iterate over the keys in the same order you inserted them then use a LinkedHashMap.
By the way, I'd recommend changing the declared type of the map to <String, List<String>>. Always best to declare types in terms of the interface rather than the implementation.
HashMaps are not ordered, unless you use a LinkedHashMap or SortedMap. In this case, you may want a LinkedHashMap. This will iterate in order of insertion (or in order of last access if you prefer). In this case, it would be
int index = 0;
for ( Map.Entry<String,ArrayList<String>> e : myHashMap.iterator().entrySet() ) {
String key = e.getKey();
ArrayList<String> val = e.getValue();
index++;
}
There is no direct get(index) in a map because it is an unordered list of key/value pairs. LinkedHashMap is a special case that keeps the order.
Kotlin HashMap Answer
You can get key by index. Then get value by key.
val item = HashMap<String, String>() // Dummy HashMap.
val keyByIndex = item.keys.elementAt(0) // Get key by index. I selected "0".
val valueOfElement = item.getValue(keyByIndex) // Get value.
You can do:
for(String key: hashMap.keySet()){
for(String value: hashMap.get(key)) {
// use the value here
}
}
This will iterate over every key, and then every value of the list associated with each key.
A solution is already selected. However, I post this solution for those who want to use an alternative approach:
// use LinkedHashMap if you want to read values from the hashmap in the same order as you put them into it
private ArrayList<String> getMapValueAt(LinkedHashMap<String, ArrayList<String>> hashMap, int index)
{
Map.Entry<String, ArrayList<String>> entry = (Map.Entry<String, ArrayList<String>>) hashMap.entrySet().toArray()[index];
return entry.getValue();
}
for (Object key : data.keySet()) {
String lKey = (String) key;
List<String> list = data.get(key);
}
I came across the same problem, read a couple of answers from different related questions and came up with my own class.
public class IndexableMap<K, V> extends HashMap<K, V> {
private LinkedList<K> keyList = new LinkedList<>();
#Override
public V put(K key, V value) {
if (!keyList.contains(key))
keyList.add(key);
return super.put(key, value);
}
#Override
public void putAll(Map<? extends K, ? extends V> m) {
for (Entry<? extends K, ? extends V> entry : m.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
#Override
public void clear() {
keyList.clear();
super.clear();
}
public List<K> getKeys() {
return keyList;
}
public int getKeyIndex(K key) {
return keyList.indexOf(key);
}
public K getKeyAt(int index) {
if (keyList.size() > index)
return keyList.get(index);
return null;
}
public V getValueAt(int index) {
K key = getKeyAt(index);
if (key != null)
return get(key);
return null;
}
}
Example (types are differing from OPs question just for clarity):
Map<String, Double> myMap = new IndexableMap<>();
List<String> keys = myMap.getKeys();
int keyIndex = myMap.getKeyIndex("keyString");
String key = myMap.getKeyAt(2);
Double value myMap.getValueAt(2);
Keep in mind that it does not override any of the complex methods, so you will need to do this on your own if you want to reliably access one of these.
Edit: I made a change to the putAll() method, because the old one had a rare chance to cause HashMap and LinkedList being in different states.
Try this:
myhashmap.entrySet()
.forEach{
println(it.getKey())
println(it.getValue())
}
or if you want by index
myhashmap.entrySet()[0].getKey()
myhashmap.entrySet()[0].getValue()
myhashmap.entrySet()[1].getKey()
myhashmap.entrySet()[1].getValue()
HashMaps don't keep your key/value pairs in a specific order. They are ordered based on the hash that each key's returns from its Object.hashCode() method. You can however iterate over the set of key/value pairs using an iterator with:
for (String key : hashmap.keySet())
{
for (list : hashmap.get(key))
{
//list.toString()
}
}
If you don't care about the actual key, a concise way to iterate over all the Map's values would be to use its values() method
Map<String, List<String>> myMap;
for ( List<String> stringList : myMap.values() ) {
for ( String myString : stringList ) {
// process the string here
}
}
The values() method is part of the Map interface and returns a Collection view of the values in the map.
You can use Kotlin extension function
fun LinkedHashMap<String, String>.getKeyByPosition(position: Int) =
this.keys.toTypedArray()[position]
fun LinkedHashMap<String, String>.getValueByPosition(position: Int) =
this.values.toTypedArray()[position]
You'll need to create multiple HashMaps like this for example
Map<String, String> fruitDetails = new HashMap();
fruitDetails.put("Mango", "Mango is a delicious fruit!");
fruitDetails.put("Guava" "Guava is a delicious fruit!");
fruitDetails.put("Pineapple", "Pineapple is a delicious fruit!");
Map<String, String> fruitDetails2 = new HashMap();
fruitDetails2.put("Orange", "Orange is a delicious fruit!");
fruitDetails2.put("Banana" "Banana is a delicious fruit!");
fruitDetails2.put("Apple", "Apple is a delicious fruit!");
// STEP 2: Create a numeric key based HashMap containing fruitDetails so we can access them by index
Map<Integer, Map<String, String>> hashMap = new HashMap();
hashMap.put(0, fruitDetails);
hashMap.put(1, fruitDetails2);
// Now we can successfully access the fruitDetails by index like this
String fruit1 = hashMap.get(0).get("Guava");
String fruit2 = hashMap.get(1).get("Apple");
System.out.println(fruit1); // outputs: Guava is a delicious fruit!
System.out.println(fruit2); // outputs: Apple is a delicious fruit!

Categories

Resources