Java - Set not printed out in order - java

I just started learning about sets, and it was mentioned that it did not care about order, unlike lists.
However, when I typed this piece of code:
public class test {
public static void main(String[] args) {
Set<Integer> nums = new HashSet<Integer>();
nums.add(0);
nums.add(1);
nums.add(2);
nums.add(3);
for (Integer num : nums)
System.out.println(num);
}
}
Based on the first line, the output should have been random, but instead it gave ordered output:
0
1
2
3
I have tried scrambling the order at which the numbers are being added, like this:
public class test {
public static void main(String[] args) {
Set<Integer> nums = new HashSet<Integer>();
nums.add(1);
nums.add(0);
nums.add(3);
nums.add(2);
for (Integer num : nums)
System.out.println(num);
}
}
Oddly though, the output was still ordered!
Is there anything that somehow sorts the set before I print its elements out?
Or is HashSet not meant for creating unordered sets?

HashSet doesn't provide any order guarantees. That doesn't mean that order can't emerge, for some data sets, as a by-product of how it is implemented. Just that you cannot rely on that, and it may change from implementation to implementation, etc.

HashSet is unordered by design. You are putting only limited small numbers which produce hash code of the value in same order. That's why it is printing in order. See the code below to see hash code and analyze it
for (Integer num : nums){
System.out.println(num + " - hashcode = " +num.hashCode());
}
Add few more large numbers to see unordered nature in action.
Example:
nums.add(29000);
nums.add(199201);

This is just a coincidence (or actually it's because how the HashSet internally works but don't care about that for now). Try adding a few more values and then removing and then adding etcetera and you will see that it doesn't print correctly. HashSet is unordered. Sets in general are unordered unless it is stated otherwise.

A HashSet is indeed an unsorted set. This means you can't assume anything about the order it's iterated over (and printed) - the same way you can't assume it will be ordered, you also can't assume it won't be. The order is completely up to the internal implementation.

Related

How to return the correct List<List<Integer>> in the subset backtracking problem

I am approaching a problem from Leetcode (78. Subsets). The method is correct, but I can't figure out how to return the correct answer.
I used the method I learned from an online course. I could accurately print out all the subsets when reaching the base case; however, I am not sure how to add those sublists into a result List<List<Integer>> and return it.
I declared a global variable and try to modify it directly, but all the subsets in it are empty. What is a good way for me to add the subsets to the result list and return it?
Here's the code:
class Solution {
List<List<Integer>> result;
public List<List<Integer>> subsets(int[] nums) {
List<Integer> chosen = new ArrayList<>();
List<Integer> numbers = new ArrayList<>();
for (int i : nums){
numbers.add(i);
}
result = new ArrayList<>();
subsetsHelper(numbers, chosen);
return result;
}
public void subsetsHelper(List<Integer> nums, List<Integer> chosen){
if (nums.size() == 0){
// System.out.println(chosen);
result.add(chosen);
}
else{
int x = nums.get(0);
nums.remove(0);
subsetsHelper(nums, chosen);
chosen.add(x);
subsetsHelper(nums, chosen);
nums.add(0, x);
chosen.remove(chosen.size()-1);
}
}
}
Here's the test case and output:
Your input
[1,2,3]
Output
[[],[],[],[],[],[],[],[]]
Expected
[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
The problem is this line
result.add(chosen);
basically you add chosen in result and then proceed to edit it in the next iterations. What you want to do is create a new list like so
result.add(new ArrayList<>(chosen));
EDIT: When you do result.add(chosen); you might think you store an arraylist chosen in result. But in fact you store the reference to the arraylist which chosen contains as its value. Adding a rough diagram to make things more clear
You might think chosen stores an entire ArrayList in itself but in reality, it just stores the reference to the arraylist which is stored in the java heap. When you make changes in chosen the changes will reflect at every place where the reference to this arraylist is stored, in your case it is in result.
The problem is that when you call return.add(chosen) you pass your chosen list to a outer list, not the inner one.
result.get(indexOfOuterList).add(chosen)
above code should work.
That's my first reply ever, sorry I tried my best.
Let me know if I was right/wrong

Collections Sort to sort both ArrayLists the same

My program has to use the Collections sort method to sort the ArrayList of Strings lexicographically but each String has a corresponding integer value stored in a separate ArrayList. I want to sort them both the same so the integer values stay with the correct Strings. And if you know a better way to store both values I'm all ears.
public class a5p1b {
public static void main(String[] args) {
Scanner input = new Scanner(System.in).useDelimiter("[^a-zA-z]+");
// ArrayLists to store the Strings and the frequencies
ArrayList<String> lst = new ArrayList<String>();
ArrayList<Integer> intLst = new ArrayList<Integer>();
//loops through as long as there is user input
while (input.hasNext()) {
String str = input.next().toLowerCase();
// if the list already has the string it doesn't add it and it
// ups the count by 1
if (lst.contains(str)) {
int index = lst.indexOf(str);
intLst.set(index, intLst.get(index) + 1);
} else {
// if the word hasnt been found yet it adds it to the list
lst.add(str);
intLst.add(1);
}
}
}
}
You are getting your abstractions wrong. If that string and that number belong together, then do not keep them in two distinct lists.
Instead create a class (or maybe use one of the existing Pair classes) that holds those two values. You can then provide an equals method for that class; plus a specific comparator, that only compares the string elements.
Finally, you put objects of that class into a single list; and then you sort that list.
The whole idea of good OO programming is to create helpful abstractions!
For the record: as dnault suggests, if there is really no "tight" coupling between strings and numbers you could also use a TreeMap (to be used as TreeMap<String, Integer>) to take care of sorting strings that have a number with them.
Try
inList.sort(Comparator.comparing(i -> i.toString());
Although, I don't think the two lists is a good idea.
You should use a Map to associate each unique String key with an Integer value.
Then you can invoke Collections.sort on the map's set of keys returned by keySet().
Additionally, if you use a SortedMap such as TreeMap, it is not necessary to sort the keys. However that solution may not fulfill the requirements of your "Assignment 5 Problem 1b."

Organizing a set of sets by size in Java

I'm writing a simple program to recursively find all subsets of some larger set. I've got it working, but I wanted to order all of the sets in order by size.
I posted my working code below.
import java.util.*;
public class AllSubsets {
public static void main(String[] args) {
// Change contents of this array to easily change contents of set.
Integer[] setContents = {3, 6, 8, 9, 10, 22};
// create initial unused set by dumping all of the aray into a set.
Set<Integer> unused = new HashSet<Integer>(Arrays.asList(setContents));
// create initial empty set for used set.
Set<Integer> used = new HashSet<Integer>();
// create output set of sets.
Set<Set<Integer>> allSets = new HashSet<Set<Integer>>();
allSets.add(used);
// find all sets recursively
findAllSets(used, unused, allSets);
// print out results
System.out.println(allSets);
}
public static void findAllSets(Set<Integer> used, Set<Integer> unused,
Set<Set<Integer>> allSets) {
if (unused != null) {
Set<Integer> copyOfUnused = new HashSet<Integer>(unused);
for (Integer val : copyOfUnused) {
unused.remove(val);
used.add(val);
allSets.add(new HashSet<Integer>(used));
findAllSets(used, unused, allSets);
used.remove(val);
unused.add(val);
}
}
}
}
I was wondering what the best way would be to order these sets by size. I tried to create a TreeSet which holds multiple HashSet objects with it's comparator method overwritten. This ended up compiling but didn't store the values correctly. The code for this I wrote is very similar to the code above, so I will write out the main difference below:
Set<Set<Integer>> allSets =
new TreeSet<Set<Integer>>(new Comparator<Set<Integer>>() {
public int compare(Set<Integer> a, Set<Integer> b) {
return a.size() - b.size();
}
});
In this version of the code, it compiles but the objects are not storing correctly. The proper sets are being computed and added to "allSets" in the recursive method (tested using println) but it only ever holds one set at a time. I have a feeling it's mostly because I overwrote the Comparator for Set but I am using HashSets. Is there a better way to organize my sets or maybe just a small bug in my code?
Thanks!!
TreeSet<Set<Integer>> will only store one Set element with a given size, because it considers two different sets with the same size to be "equal": it takes a.compareTo(b) == 0 to mean a == b.
If you want to get all of the sets and then print them in order of size, gather all of the sets in a regular (Hash)Set, and then sort the entries:
List<Set<Integer>> listOfSets = new ArrayList<>(allSets);
Collections.sort(listOfSets, <your comparator above>);
System.out.println(listOfSets).

Remove duplicates in an array without changing order of elements

I have an array, say List<Integer> 139, 127, 127, 139, 130
How to remove duplicates of it and keep its order unchanged? i.e. 139, 127, 130
Use an instance of java.util.LinkedHashSet.
Set<Integer> set = new LinkedHashSet<>(list);
With this one-liner:
yourList = new ArrayList<Integer>(new LinkedHashSet<Integer>(yourList))
Without LinkedHashSet overhead (uses HashSet for seen elements instead which is slightly faster):
List<Integer> noDuplicates = list
.stream()
.distinct()
.collect(Collectors.toList());
Note that the order is guaranteed by the Stream.distinct() contract:
For ordered streams, the selection of distinct elements is stable (for
duplicated elements, the element appearing first in the encounter
order is preserved.)
Construct Set from your list - "A collection that contains no duplicate elements":
Set<Integer> yourSet = new HashSet<Integer>(yourList);
And convert it back to whatever you want.
Note: If you want to preserve order, use LinkedHashSet instead.
Use LinkedHashSet to remove duplicate and maintain order.
As I cant deduct, you need to preserve insertion order, that compleating what #Maroun Maroun wrote, use set, but specialidez implementation like LinkedHashSet<E> whitch does exactly the thing you need.
Iterate through array (via iterator, not foreach) and remove duplicates. Use set for find duplicates.
OR
Iterate through array and add all elements to LinkedHashSet, it isn't allows duplicates and keeps order of elements.
Then clear array, iterate through set and add each element to array.
Although converting the ArrayList to a HashSet effectively removes duplicates, if you need to preserve insertion order, I'd rather suggest you to use this variant
// list is some List of Strings
Set<String> s = new LinkedHashSet<String>(list);
Then, if you need to get back a List reference, you can use again the conversion constructor.
There are 2 ways:
create new list with unique ints only
(the same as Maroun Maroun answer)
you can do it with 2 nested fors like this O(n.n/2):
List<int> src,dst;
// src is input list
// dst is output list
dst.allocate(src.num); // prepare size to avoid slowdowns by reallocations
dst.num=0; // start from empty list
for (int i=0;i<src.num;i++)
{
int e=1;
for (int j=0;i<dst.num;i++)
if (src[i]==dst[j]) { e=0; break; }
if (e) dst.add(src[i]);
}
You can select duplicate items and delete them ... O(2.n) with the flagged delete
this is way much faster but you need memory table for whole int range
if you use numbers <0,10000> then it will take BYTE cnt[10001]
if you use numbers <-10000,10000> then it will take BYTE cnt[20002]
for small ranges like this is ok but if you have to use 32 bit range it will take 4GB !!!
with bit packing you can have 2 bits per value so it will be just 1GB but that is still too much for my taste
ok now how to check for duplicity ...
List<WORD> src; // src is input list
BYTE cnt[65536]; // count usage for all used numbers
int i;
for (i=0;i<65536;i++) cnt[i]=0; // clear the count for all numbers
for (i=0;i<src.num;i++) // compute the count for used numbers in the list
if (cnt[src[i]]!=255)
cnt[src[i]]++;
after this any number i is duplicate if (cnt[i]>1)
so now we want to delete duplicate items (all except one)
to do that change cnt[] like this
for (i=0;i<65536;i++) if (cnt[i]>1) cnt[i]=1; else cnt[i]=0;
ok now comes the delete part:
for (i=0;i<src.num;i++)
if (cnt[src[i]]==1) cnt[src[i]]=2; // do not delete the first time
else if (cnt[src[i]]==2) // but all the others yes
{
src.del(i);
i--; // indexes in src changed after delete so recheck for the same index again
}
you can combine both approaches together
delete item from list is slow because of item shift in the list
but can be speed up by adding delete flag to items
instead of delete just set the flag
and after all items to delete is flagged then simply remove hem at once O(n)
PS. Sorry for non standard list usage but i think the code is understandable enough if not comment me and i respond
PPS. for use with signed values do not forget to shift the address by half range !!!
Below I have given the sample example that implements a generic function to remove duplicate from arraylist and maintain the order at the same time.
import java.util.*;
public class Main {
//Generic function to remove duplicates in list and maintain order
private static <E> List<E> removeDuplicate(List<E> list) {
Set<E> array = new LinkedHashSet<E>();
array.addAll(list);
return new ArrayList<>(array);
}
public static void main(String[] args) {
//Print [2, 3, 5, 4]
System.out.println(removeDuplicate(Arrays.asList(2,2,3,5, 3, 4)));
//Print [AB, BC, CD]
System.out.println(removeDuplicate(Arrays.asList("AB","BC","CD","AB")));
}
}
Method 1 : In Python => Using a set and list comprehension
a= [139, 127, 127, 139, 130]
print(a)
seen =set()
aa = [ch for ch in a if ch not in seen and not seen.add(ch)]
print(aa)
Method 2 :
aa = list(set(a))
print(aa)
In Java : using Set and making a new ArrayList
class t1 {
public static void main(String[] args) {
int[] a = {139, 127, 127, 139, 130};
List<Integer> list1 = new ArrayList<>();
Set<Integer> set = new LinkedHashSet<Integer>();
for( int ch : a) {
if(!set.contains(ch)) {
set.add(ch);
}
}//for
set.forEach( (k) -> list1.add(k));
System.out.println(list1);
}
}
Bro this is you answer but this have 0(n2) T.C remember.
vector<int> sol(int arr[],int n){
vector<int> dummy;
for(int i=0;i<n-1;i++){
for(int j=i+1;j<n;j++){
if(arr[i]==arr[j]){
dummy.push_back(j);
}
}
}
vector<int> ans;
for(int i=0;i<n;i++){
bool check=true;
for(int j=0;j<dummy.size();j++){
if(dummy[j]==i){
check=false;
}
}
if(check==false)
continue;
ans.push_back(arr[i]);
}
return ans;
}

Java: Why subList(0, 5).clear() doesn't work on my objects?

If I run this operation on List<Integer> for example, it works as expected (removes first 5 elements), but when I run it on a list of my objects, nothing happens (list stays the same).
list.subList(0, 5).clear();
My class is a pojo that doesn't implement equals or hashCode, if that matters.
UPDATE:
The implementation I am using is ArrayList, which is returned from Hibernate query. There is nothing to show, really. Sublist doesn't return an empty list.
Here is an example for those who don't beleive it works on a list of Integers:
List<Integer> testList = new ArrayList<Integer>();
for(int i=0;i<10;i++) {
testList.add(i);
}
testList.subList(0, 5).clear();
for(int i=0;i<testList.size();i++) {
System.out.print(testList.get(i)+" ");
}
The result is 5 6 7 8 9
UPDATE2: Actually everything is working as expected, don't know how I couldn't see that (got confused by numbers of results). Sorry for false alarm :) This question could be deleted.
It works on my machinetm
import java.util.*;
import static java.lang.System.out;
class SubListExample {
public static void main( String [] args ) {
List<RandomObject> testList = new ArrayList<RandomObject>();
for(int i=0;i<10;i++) {
testList.add( new RandomObject() );
}
System.out.println( "Before: " + testList );
testList.subList(0, 5).clear();
System.out.println( "After: "+ testList );
}
}
class RandomObject {
static Random generator = new Random();
int id = generator.nextInt(100);
public String toString(){
return "ro("+id+")";
}
}
Produces:
$ java SubListExample
Before: [ro(68), ro(97), ro(48), ro(45), ro(43), ro(69), ro(45), ro(8), ro(88), ro(40)]
After: [ro(69), ro(45), ro(8), ro(88), ro(40)]
So, the problem is not in ArrayList nor in your objects.
I don't think Hibernate returns a plain old ArrayList ( may be it does )
Try printing
System.out.println( "That hibernate list.class.name = "
+ listReturnedByHibernate.getClass().getName() );
And let us know if it is in fact an ArrayList
edit - Looks like I was wrong, but leaving my original answer here anyway:
Are you sure that it works with a List<Integer>? It shouldn't.
The method subList() returns a separate List. If you remove elements from that list, it shouldn't affect the original list. The API docs for List.subList() say this:
Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive. (If fromIndex and toIndex are equal, the returned list is empty.) The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa.
Clearing a list is not a non-structural change; only changing the elements in the list are non-structural changes.
This has nothing to do with whether your POJO has equals or hashCode methods or not.
edit - I just tried it out with an ArrayList and it does work (not only with Integer, but also with my own object as a list element).
Two things I can think of are:
list.sublist(0, 5) returns an empty list, therefore .clear() does nothing.
Not sure of the inner workings of the List implementation you're using (ArrayList, LinkedList, etc), but having the equals and hashCode implemented may be important.
I had a simiarl issue with Maps, where HashMap definitely needs the hashCode implementation.
Have you tried creating a List of your objects manually and doing the same thing (without Hibernate)? It seems possible to me that this has to do with Hibernate's lazy loading of data... if you haven't read the data in the returned List, it may not have been loaded yet (since sublists themselves are just views). In that case, it's possible clear would do nothing.
Is it possible that the List returned from Hibernate is not modifiable? i.e. wrapped by Collections.unmodifiableList()

Categories

Resources