I need to create a collection of unique collection in java. Could someone please suggest possible containers for the same.
I want to have something like List<List<int>> where each each of the list could repeat itself in terms of its contents.
For example if my current state of the parent list is say
[ [1,2,3], [3,4,5], [4,5,6] ] and if I intend to add another list say [3,4,5] to it, it should not be duplicated and should not be added.
contains() method of List will work with integers, floats etc, but I am not sure if it will be able to match lists.
Please suggest any other container which could help.
Thanks.
You'll probably be best off using Set<List<Integer>> instead of List<List<Integer>>.
The above applied to your example:
Set<List<Integer>> uniqueLists = new HashSet<>();
uniqueLists.add(Arrays.asList(1, 2, 3));
uniqueLists.add(Arrays.asList(3, 4, 5));
uniqueLists.add(Arrays.asList(4, 5, 6));
// Now, this won't be added:
uniqueLists.add(Arrays.asList(3, 4, 5));
Be careful when you put a collection inside a set, though. You should not change it again, after you have put it in the set.
Perhaps you would be interested to use Set<Set<Integer>>.
In case you would like to maintain the addition order, you can use LinkedHashSet.
Your code will be like
Set<Set<Integer> uniqueLists = new LinkedHashSet<Set<Integer>>();
uniqueLists.add(new LinkedHashSet(Arrays.asList(1, 2, 3)));
It would avoid two problems from using Set<List<Integer>>.
1) It would retains addition order of the individual lists
2) It individual list will also not have duplicate integer entries.
Related
fairly new person to Java here, I’d like to ask if there’s a way to add an element between two elements or be able to shift all elements to the right or left of an ArrayList and how I could figure out the middle.
For example if I have [3, 5, 8, 10] and I want to insert the number 6, how would I figure out where it fits in ascending order?
Thanks so much
Depends on your need, do you necessary need an ArrayList?
#1) If you need sorting but is the number unique? The provided example is (3, 5, 8, 10) and to add (6). If there is another '3', should the result return (3,3,5,6,8,10)? If NOT, why not consider a NavigableSet/SortedSet such as TreeSet ?
import java.util.*;
...
NavigableSet<Integer> navSet = new TreeSet<>(Arrays.asList(new Integer[]{3,5,8,10});
navSet.add(6); //you'll get 3,5,6,8,10
navSet.add(6); //still get 3,5,6,8,10 -- no extra 6
#2) Is the number non unique but to be ordered ? There is a collection provided by Apache for BAG(combining Set and List). Apache Commmons Collection Bag
import org.apache.commons.collections4.Bag;
import org.apache.commons.collections4.bag.TreeBag;
...
Bag<Integer> treeBag = new TreeBag<>(Arrays.asList(new Integer[]{3,5,6,8,10});
treeBag.add(6); //you'll get 3,5,6,6,8,10
#3) Else if you really need to code it manually. There is always a Collections util to sort it after you add, e.g.
import java.util.*;
List<Integer> arrayList = Arrays.asList(new Integer[]{3,5,5,8,10});
List sortedList = arrayList.stream().parallel().sorted()collect(Collectors.toList());
//you'll get (3,5,5,6,8,10), as it gets sorted again.
Finally, the sorting above for #2 and #3 is always slower as there is an add then re-sort. If you want something that optimized via search while rebuilding the list, like Stephen P provided in the other answer, it may be a better solution. But as always consider your implementation.
*To preface, I posted a similar question but this time, the output I want is going to be different.
Suppose we have a person named Bob, and he has a list of integers he wrote down:
bobList = [10, 25, 30, 50]
Say there are 3 other lists of random integers that was generated by a system and put into 1 master list:
list1 = [1, 10, 20, 25, 33, 55]
list2 = [2, 3, 5, 6, 9, 30]
list3 = [25, 30, 50, 100]
List<List<Integer>> masterList = new ArrayList<>()
masterList.add(list1)
masterList.add(list2)
masterList.add(list3)
It can be assumed that the 3 list of numbers generated by a system are in order from smallest to greatest and Bob's list is also from smallest to greatest. The goal is to go through Bob's list and see if each number written down by Bob is contained in each list within the master list. I tried this with Java 11 with streams to try and show whether or not each integer in Bob's list belongs in each of the 3 lists by trying to output it like
{10=[true, false, false], 25=[true, false, true], 30=[false, true, true] , 50=[false, false, true]}
I think this will be something like Bob's list but with each integer he wrote being the key, and the value being a list of Boolean where each index is the corresponding list, and if its true then that number Bob wrote is in the list and vice versa for false. But the problem is, I'm sort of new to programming and in my mind, all this data structure and algorithms is really messing with me and I've been stuck on this for the past day now. Could someone post a solution to this where the output will look like the one described? Or if you have a better recommendations for a output that has a easier view then by all means, I'm definitely looking to improve it! Thank you!
Update: I totally forgot to add my attempt but I played around with this piece:
List<Map<Boolean, List<Integer>>> test = bobList.stream()
.map(list -> list.stream()
.collect(Collectors.partitioningBy(masterList::contains)))
.collect(Collectors.toList());
test.forEach(System.out::println);
The output is something like:
{false=[1,20,33,55], true=[10,25]}
{false=[2,3,5,6,9], true=[30]}
{false=[100], true=[25,30,50]}
As you can see, this way compares the 3 lists in masterList to bobList and outputs it like false and true and splits whichever numbers are in bobList and whichever are not. However, I tried flipping it and seeing which numbers in bobList are in the masterList's lists and outputting it like the way I wanted, but I just get stuck and circle around with different attempts
A partial solution I had was going from boblist to just 1 list using :
masterList.stream().map(l -> l.contains(i)).collect(Collectors.toList()))));
But i'm unsure where to get that respective key for the list.
Update: Thank you to Holger, I forgot you could use .collect() twice
Try to break down the problem into steps, and implement each step! (Pseudo code helps a lot) :) I'll give you a little hint:
Your goal here is to iterate through bobList and check whether list1, list2, and list3 (via iterating through the Masterlist) has the integer, and print that result. You could iterate with for loops for example.
How can you check if a list contains that integer? Could something like list.contains() method help?
As for the output, You can output it whatever you want, as long as it looks nice and meets the criteria.
for example if you want to be a little bit fancy with your output:
10: |true|false|false|
You could print the boolean immediately during the iterations inside the for-loop.
If you would like to do this with streams then the solution is to stream bobList and collect the stream as a map. The values in the map can themselves be generated by streaming masterList and mapping to boolean representing whether the key is in the associated list.
Putting all that together:
Map<Integer,List<Boolean>> result = bobList.stream()
.collect(Collectors.toMap(
i -> i,
i -> masterList.stream().map(l -> l.contains(i)).collect(Collectors.toList()))));
As suggested by Holger: l.contains(i) could be replaced by Collections.binarySearch(l, i) >= 0 which speeds up the search by relying on the fact that it is pre-sorted. But unless your lists are going to be long or this map will be constructed many times I would expect the difference would be minimal.
You also mention in comments (rather than original question) that you want key order to be maintained. You could do this by explicitly using LinkedHashMap.
While it is easy to do it in a for loop, is there a way in Java-8 to find if all elements in list L are present in Set s ?
There's no need to use a Stream for this when you can use Set#containsAll:
var set = Set.of(1, 2, 3, 4, 5);
var list = List.of(2, 3, 4);
System.out.println(set.containsAll(list));
Output:
true
You can use allMatch:
boolean result = l.stream().allMatch(s::contains);
Yes.
long commonElements = l.stream().filter(s::contains).count();
if (commonElements == l.size()) {
//do something
}
Sets are nice because they are built for exactly this kind of thing: checking if an item exists already. Lists are not as good at this practice, but are good for quick traversal. So, you want to loop through the list and compare each element to the set, vs the other way around.
Streams are a nice resource for performing operations in-line vs explicitly breaking things out.
EDIT: #Aomine 's answer is better than mine
boolean result = myList.stream().allMatch(mySet::contains);
I have an sorted array consisting elements (1,1,2,3,3,4). I want to get unique elements from this array and length of the resulting array.
Output array should consists (1,2,3,4) and size = 4.
If you are using Java 8, you can do it in the following way:
Arrays.stream(arr).distinct().toArray();
DEMO
The easiest thing to do here might be to just add your array elements to a sorted set, e.g. TreeSet:
int[] array = new int[] {1, 1, 2, 3, 3, 4};
Set<Integer> set = new TreeSet<>();
for (int num : array) {
set.add(num);
}
This option would make good sense if your code also had a need to work with a set later on at some point.
Is this for homework? If it is, please say so. I'm going to assume it is.
I would traverse the array and use a List to store values that I have already seen. If I come across a value that already appears in my List, I'll skip it. If not, I'll add it. Then I'll convert the list to an array and return it. I'm not going to write it for you because I'm assuming it's homework, but that is the basic idea.
NOTE: If performance is a concern, use a HashMap instead of a List.
I have an ArrayList of ArrayLists implemented as:
ArrayList<ArrayList<Integer>> sampleList = new ArrayList<ArrayList<Integer>>();
Supposing that my list, after some operations, contains the following elements:
[[1,2,3],[2,1,3,4],[3,1,2],[4,2]]
I want to remove all occurrences of a particular element, say 4, from this collection, i.e., I want to obtain the following output after the removal of 4:
[[1,2,3],[2,1,3],[3,1,2]]
I know I can use a for loop, but that would be too tedious and inefficient in cases of a really large set.
So is there a better method to do this? (I'm new to programming)
Given your stated requirements, there's not going to be a better solution. You'll need to be a bit careful to avoid removing the value 4 instead of the element at position 4:
Set<String> toRemove = Collections.singleton(4);
for (List<Integer> list : sampleList) {
list.removeAll(toRemove);
}