Putting HashSet inside a HashMap - java

Is there any way to reuse a hash set by adding it to the HashMap, then later changing the HashSet without it changing the previous HashSet that was placed into the hashMap?
public static void hash() {
HashMap<Integer, HashSet<Integer>> hset = new HashMap<Integer, HashSet<Integer>>(
HashSet<Integer> list = new HashSet<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
hset.put(1,list);
System.out.println(hset.get(1));
// the console prints "[1, 2, 3, 4]"
list.clear();
System.out.println(hset.get(1));
// the console prints "[]"
}
I want to take user inputs for the HashSet, store them in the HashMap, then clear the HashSet to be used again by the user. But I need to use the same HashSet as there will be a loop.

Put a new HashSet consisting of the elements of list.
hset.put(1, new HashSet<>(list));
Demo:
import java.util.HashMap;
import java.util.HashSet;
public class Main {
public static void main(String[] args) {
HashMap<Integer, HashSet<Integer>> hset = new HashMap<>();
HashSet<Integer> list = new HashSet<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
hset.put(1, new HashSet<>(list));
System.out.println(hset.get(1));
// the console prints "[1, 2, 3, 4]"
list.clear();
System.out.println(hset.get(1));
// the console prints "[1, 2, 3, 4]"
}
}
On a side note, you need just <> on the right side i.e. instead of new HashMap<Integer, HashSet<Integer>>, you can simply write new HashMap<>.

Parameter passing is done by reference in Java.
HashSet object in your Hashmap and HashSet object in the list variable are the same!

I would recommend you do not clear the HashMap but rather add a new instance of the HashSet into the HashMap as your loop continues. like below.
public static void hash() {
HashMap<Integer, HashSet<Integer>> hset = new HashMap<Integer, HashSet<Integer>>()
int mapKey = 1;
//loop here , create the instance of HashSet for every loop operation
while(true){
HashSet<Integer> list = new HashSet<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
hset.put(mapKey,list);
System.out.println(hset.get(mapKey));
// the console prints "[1, 2, 3, 4]"
//list.clear();
System.out.println(hset.get(map.getKey));
// the console prints "[]"
mapKey++;
}
}
The MapKey would be different for the different HashSets you will have.

Related

remove duplicate list from an arrayList using Set

I have a List that contains duplicate ArrayList.
I'm looking for a solution to remove them.
Here is an example:
listOne = [[1, 0], [0, 1], [3, 2], [2, 3]]
This set contains duplicate List. Normally i want to get :
theListAfterTransformation = [[1, 0],[3, 2]]
Here is my tiny example, i tried to use the Set but it didn't work well.
public class Example {
public static void main( String[] args ) {
ArrayList<ArrayList<Integer>> lists = new ArrayList<>();
ArrayList<Integer> list1 = new ArrayList<>(); list1.add(1); list1.add(0);
ArrayList<Integer> list2 = new ArrayList<>(); list2.add(0); list2.add(1);
ArrayList<Integer> list3 = new ArrayList<>(); list3.add(3); list3.add(2);
ArrayList<Integer> list4 = new ArrayList<>(); list4.add(2); list4.add(3);
lists.add(list1);lists.add(list2);lists.add(list3);lists.add(list4);
System.out.println(getUnduplicateList(lists));
}
public static ArrayList<ArrayList<Integer>> getUnduplicateList( ArrayList<ArrayList<Integer>> lists) {
Iterator iterator = lists.iterator();
Set<ArrayList<Integer>> set = new HashSet<>();
while (iterator.hasNext()){
ArrayList<Integer> list = (ArrayList<Integer>) iterator.next();
set.add(list);
}
return new ArrayList<>(set);
}
}
Note that is a tiny example from my project and it will be very hard to use a solution that change many thing in this implementation.
So take into account that the getUnduplicateList should keep the same signature. the good idea will be to change only the implementation.
This program print the same list as the input. any idea please.
A couple notes on terminology—Set is a distinct data structure from List, where the former is unordered and does not allow duplicates, while the latter is a basic, linear collection, that's generally ordered, and allows duplicates. You seem to be using the terms interchangeably, which may be part of the issue you're having: Set is probably the appropriate data structure here.
That said, it seems that your code is relying on the List API, so we can follow that along. Note that you should, in general, code to the interface (List), rather than the specific class (ArrayList).
Additionally, consider using the Arrays.asList shorthand method for initializing a list (note that this returns an immutable list).
Finally, note that a HashSet eliminates duplicates by checking if both objects have the same hashCode. Lists containing the same elements are still not considered to be the same list unless the elements appear in the same order, and will typically not be treated as duplicates. Sets, however, implement equals and hashCode in such a way that two sets containing exactly the same elements are considered equal (order doesn't matter).
Using your original starting collection, you can convert each inner-list to a set. Then, eliminate duplicates from the outer collection. Finally, convert the inner-collections back to lists, to maintain compatibility with the rest of your code (if needed). This approach will work regardless of the size of the inner-lists.
You can simulate these steps using a Stream, and using method references to convert to and from the Set, as below.
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.stream.Collectors;
public class Example {
public static void main( String[] args ) {
List<Integer> list1 = Arrays.asList(1, 0);
List<Integer> list2 = Arrays.asList(0, 1);
List<Integer> list3 = Arrays.asList(3, 2);
List<Integer> list4 = Arrays.asList(2, 3);
List<List<Integer>> lists = Arrays.asList(list1, list2, list3, list4);
System.out.println(getUnduplicateList(lists));
}
public static List<List<Integer>> getUnduplicateList(List<List<Integer>> lists) {
return lists
.stream()
.map(HashSet::new)
.distinct()
.map(ArrayList::new)
.collect(Collectors.toList());
}
}
You need to convert the inner lists to sets as well.
Another solution is to sort your lists and then run them through distinct Although this is not very efficient and you will also obtain a set of sorted lists:
Set<List<Integer>> collect = set.stream()
.map(list -> {
list.sort(Comparator.comparingInt(Integer::intValue));
return list;
})
.distinct()
.collect(Collectors.toSet());

Collections.sort sorts the wrong list

I want to create one sorted list out of my original list - without the Collections.sort(list) call changing the original list. So that I have one list unsorted and one being sorted - out of the same list.
Take a look at this code:
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList();
list.add(5);
list.add(8);
list.add(3);
list.add(6);
System.out.println("Before method list is");
System.out.println(list);
ArrayList<Integer> theReturnedList = sorted(list);
System.out.println("After it is");
System.out.println(list);
}
private static ArrayList<Integer> sorted(ArrayList<Integer> list){
ArrayList<Integer> returnList = list;
Collections.sort(returnList);
return returnList;
}
The list object gets sorted - even though I am not calling the Collection.sort() method onto it. How can I avoid it?
Beacuse I thought this would happen...
public static void main(String[] args) {
String original = "I am an object created in main";
String theChangedObject = change(original);
System.out.println(original);
}
private static String change(String string){
String changed = string;
changed = "I was changed";
return changed;
}
The object orginal stays the same.
Your problem is a misunderstanding of how references work. Let's take a look at the method:
private static ArrayList<Integer> sorted(ArrayList<Integer> list){
ArrayList<Integer> returnList = list;
Collections.sort(returnList);
return returnList;
}
The line ArrayList<Integer> returnList = list; does not copy the list. It copies the reference to the list. What this means is that returnList and list will both refer to the same list. Changes in one will affect the other, because they are actually just different names for the same thing.
What you want to do is to make a brand new list containing the same values, which can be done with
ArrayList<Integer> returnList = new ArrayList<>();
returnList.addAll(list);
There is also a convenient ArrayList constructor that does this in one step:
ArrayList<Integer> returnList = new ArrayList<>(list);
Changes to returnList will not affect list because they are now two completely independent lists that just happen to contain the same values.
In your sorted method you are still calling Collection.sort on the original list. To avoid this you could create a shallow copy and return that e.g.
private static ArrayList<Integer> sorted(ArrayList<Integer> list){
ArrayList<Integer> returnList = new ArrayList<>(list);
Collections.sort(returnList);
return returnList;
}
On this line:
ArrayList<Integer> returnList = list;
you are just creating another reference to the same list (Object) in your sorted method and any change that you apply to it using this new reference will be reflected in you original reference because they point to the same object. You can do this to create a new list:
private static ArrayList<Integer> sorted(ArrayList<Integer> list){
ArrayList<Integer> returnList = new ArrayList<>(list); // the new keyword creates a new object on the memory heap
Collections.sort(returnList);
return returnList;
}
This time we are creating another ArrayList Object with the elements of you original list. This way the original list won't change when you sort the newer.
This behaviour doesn't apply on Immutable Objects like String or LocalDateTime. These cannot change their state after being created and instead return a new copy with the changes applied.
you can use Stream api
List<Integer> list = Arrays.asList(5,8,3,6);
List<Integer> newList = list.stream().sorted().collect(Collectors.toList());
The stream api offers several methods to work with collections immutably. This is the recommended way if you are using Java 8 or later.

Convert 2D arraylist to hashmap in Java

I have a small question about converting 2d arraylist to hashmap in java. I have a dataset looks like this after reading as 2d arraylist:
0 1
0 2
1 2
1 3
Which first column stands for id and second column stands for the item. I would like to create frequent itemset using hashmap in java, the output should look like
1 0
2 0 1
3 1
I use these codes but I have some trouble on them:
HashMap<Integer, ArrayList<Integer>> map = new HashMap<Integer, ArrayList<Integer>>();
for(Integer elem : data){
map.put(elem[1], elem[0]);
}
Where data is my 2d arraylist.
The error message said that
incompatible types: ArrayList<Integer> cannot be converted to Integer
for(Integer elem : data){
^
Any help will be appreciated!
You go like this:
List<List<Integer>> inputData = ...
Map<Integer, List<Integer>> dataAsMap = new HashMap<>();
for(List<Integer> row : data){
Integer id = row.get(0);
Integer item = row.get(1);
List<Integer> rowInMap = dataAsMap.get(item);
if (rowInMap == null) {
rowInMap = new ArrayList<>();
dataAsMap.put(item, rowInMap);
}
rowInMap.add(id);
}
Some notes:
You should only be using the interface types List, Map ... as types (you only specify the specific impl type such as HashMap when creating new objects!)
Your problem is: when using for-each on List of Lists (as you did) ... you don't get the individual "cells" Instead, you get Lists [ iterating lists of lists ... results in one list per iteration!]
So, what is left then is to fetch the elements of that inner List, and push them into the Map. The one other part to pay attention to: you want to create a Map of List objects. And those List objects need to be created as well!
( I didn't run the above through a compiler, so beware of typos, but in general it should be telling you what you need to know. If you don't get what the code is doing, I suggest adding println statements or running it in a debugger)
Here is one easy way of doing it:
Take Map<Integer, List<Integer>>
Iterate your Arraylist.
See if key is already present in the map. Retrieve the list and add the value to the list if key is present or else create a new list with the value.
Program:
class FooBar {
public static void main (String[] args) throws Exception {
int[][] data = {{0,1}, {0,2}, {1,2}, {1,3}};
Map<Integer, List<Integer>> myMap = new HashMap<>();
for(int i = 0; i < 4; i++) {
List<Integer> values = myMap.containsKey(data[i][0]) ?
myMap.get(data[i][0]) : new ArrayList<>();
values.add(data[i][1]);
myMap.put(data[i][0], values);
}
System.out.println(myMap);
}
}
Output:
{0=[1, 2], 1=[2, 3]}
This is just to illustrate the basic method. You can obviously modify it to suit your needs. For example, you can have String instead of List<Integer> and choose to append the values to the String instead of adding it to the List.
EDIT:
Here is a sample program with List<List<Integer>> as input. Here I'm assuming the name of this list as input.
Program:
class FooBar {
public static void main (String[] args) throws Exception {
/* Input Data */
List<List<Integer>> input = new ArrayList<>();
input.add(new ArrayList<Integer>(){{add(0); add(1);}});
input.add(new ArrayList<Integer>(){{add(0); add(2);}});
input.add(new ArrayList<Integer>(){{add(1); add(2);}});
input.add(new ArrayList<Integer>(){{add(1); add(3);}});
Map<Integer, List<Integer>> myMap = new HashMap<>();
for(int i = 0; i < input.size(); i++) {
List<Integer> values = myMap.containsKey(input.get(i).get(0)) ?
myMap.get(input.get(i).get(0)) : new ArrayList<>();
values.add(input.get(i).get(1));
myMap.put(input.get(i).get(0), values);
}
System.out.println(myMap);
}
}
Output:
{0=[1, 2], 1=[2, 3]}

Array of references to ArrayList Object

I want to know the shortcut for doing this :
class{ ArrayList a1=new ArrayList();
ArrayList a2=new ArrayList();
ArrayList a3=new ArrayList();
.....& so on
}
So instead of writing each reference, how can I write an array of references 'with ArrayList' ?
you can use `List<ArrayList> list = new ArrayList<ArrayList>();`. In this you can add any number of `ArrayList` Objects to `list` reference.
Find the below :
List<ArrayList> list = new ArrayList<ArrayList>();
list.add(new ArrayList());
list.add(new ArrayList());
list.add(new ArrayList());
list.add(new ArrayList());
// ....
list hold ArrayList references in inserted order. You can access the ArrayList using index which zero based.
// to access the ArrayList reference.
ArrayList a1 = list.get(0);
Use an array of ArrayList. And loop.
ArrayList a1, a2, ... , a100;
ArrayList[] arrayLists = new ArrayList[100];
for (ArrayList arrayList : arrayLists) {
arrayList = new ArrayList();
}
But creating different references array is not a good design.
For example you can create array list array like below:
ArrayList[] a = new ArrayList[4];
Before implementing this you clear with your requirement , why you need to create these many references.
And also while creating ArrayList it's better to use reference creation like below:
List<String> a = new ArrayList<String>();
Always use generics while working on JAVA collections.
For your requirement to store word and it's permutations, I would suggest below process:
Step1: Create WordPermutations class
public Class WordPermutations{
public string word;
public ArrayList<String> permutations = new ArrayList<String>();
public void setWord(String word){
this.word = word;
}
public void setPermutations(ArrayList<string> permutations){
this.permutations = permutations;
}
public String getWord(){
return this.word;
}
public ArrayList<String> getPermuatations(){
return this.permuations;
}
}
Step2: Use this class to create your arrayList objects like below:
Class MainPermutation{
public static void main(String args[]){
// your code to get all your words and their permutations
// Now add them like below
ArrayList<WordPermutations> words = new ArrayList<WordPermutations>();
//your loop to iterate words and their permutations
for (int i=0;i<words.length;i++){
WordPermutations wordP = new WordPermutations();
wordP.setWord(word); //String word
wordP.setPermutations(permutations); //arraylist of permutations
words.add(wordP); //adding your word and it's permutations to class
}
}
}
Step3: Now read your arrayList array accordingly
with above process you can store n number of words.
Hope it helps you.

Combining ArrayList without duplicates

import java.util.ArrayList;
import java.util.Collections;
public class SmartCombining {
public static void main(String[] args) {
ArrayList<Integer> list1 = new ArrayList<Integer>();
ArrayList<Integer> list2 = new ArrayList<Integer>();
Collections.addAll(list1, 4, 3);
Collections.addAll(list2, 5, 10, 4, 3, 7);
smartCombine(list1, list2);
System.out.println(list1);
System.out.println(list2);
}
public static void smartCombine(ArrayList<Integer> first,
ArrayList<Integer> second) {
first.addAll(second);
}
}
So, I want to combine two lists into one, but if the second list contains a number from the first it won't be added. So far my method adds them all together.
Well, one way to do it is to iterate through the second list while checking if each element exists in the first list. If it doesn't, add it.
public static void smartCombine(ArrayList<Integer> first, ArrayList<Integer> second) {
for(Integer num : second) { // iterate through the second list
if(!first.contains(num)) { // if first list doesn't contain current element
first.add(num); // add it to the first list
}
}
}
Another way would be for you to hold your values inside a set (like HashSet) which doesn't allow any duplicates. Then you can combine them like:
first.addAll(second);
One more way you could do it is to first remove all elements from the first list that exist in the second list (the ones that would be duplicated). Then you add all elements of the second list to the first list.
public static void smartCombine(ArrayList<Integer> first, ArrayList<Integer> second) {
first.removeAll(second); // remove elements that would be duplicated
first.addAll(second); // add elements from second list
}
The simple, no brains solution:
Set<Integer> joinedSet = new HashSet<Integer>();
joinedSet.addAll(list1);
joinedSet.addAll(list2);
Remove duplicates, then merge both lists:
list1.remove(list2);
list1.addAll(list2);
If you dont want to alter the original list, then first create a backup:
list1BP = new ArrayList(list1);
Another approach is to use HashSet, see other answers.
Use Set, it has been created for that purpose. A Set cannot contain 2 identical elements, based on the equals method.
Set<Integer> list1 = new HashSet<Integer>();
Set<Integer> list2 = new HashSet<Integer>();
Using a combination of ArrayList and contains method is an antipattern here.
There are two easy way you can combine two Lists and duplicate will be removed.
1) First and very easiest way you can get your output, by creating equivalent HashSet object of your ArrayList. Since HashSet does not allow duplicates.
public static void main(String[] args) {
ArrayList<Integer> list1 = new ArrayList<Integer>();
ArrayList<Integer> list2 = new ArrayList<Integer>();
Collections.addAll(list1, 4, 3);
Collections.addAll(list2, 5, 10, 4, 3, 7);
System.out.println(smartCombine(list1, list2));
}
public static HashSet<Integer> smartCombine(ArrayList<Integer> first, ArrayList<Integer> second) {
first.addAll(second);
HashSet<Integer> hs = new HashSet<Integer>(first);
return hs;
2) There is another way using advanced for loop. Iterate the second list and check if the current element is not in first list and then add the current element.
public static void main(String[] args) {
ArrayList<Integer> list1 = new ArrayList<Integer>();
ArrayList<Integer> list2 = new ArrayList<Integer>();
Collections.addAll(list1, 4, 3);
Collections.addAll(list2, 5, 10, 4, 3, 7);
smartCombine(list1, list2);
System.out.println(list1);
}
public static void smartCombine(ArrayList<Integer> first, ArrayList<Integer> second) {
for (Integer num : second) {
if (!first.contains(num)) {
first.add(num);
}
}
}
Note: The second way will work fine only if first list has no duplicates.
Have you tried ArrayList.addAll()
Look at this java doc
As pointer out this would not handle duplicates which can easily be removed using a Set
use contains(Object) method in ArrayList
public static void smartCombine(ArrayList<Integer> first,
ArrayList<Integer> second) {
for(Integer i :second){
if(!first.contains(i)) { // if first list doesn't contain this item, add item to the first list.
first.add(i);
}
}
}

Categories

Resources