Related
This question already has answers here:
Remove first N occurrence of an element from a List
(4 answers)
Remove first N selectively from list using java 8
(3 answers)
Closed last year.
I have an ArrayList and I have to remove the first 2 instances of number 1
public void remove(int num, int element) {
ArrayList<Integer> arr = [1, 2, 1, 2, 1];
// ...
}
element is the number inside myArray, num is how many times I have to remove the element.
So if num is 2 and element is 1, the ArrayList will contain [2, 2, 1]
How can I do it? I've tried a for loop but I don't know how to write the 'how many times'. Thank you
First, it may be needed to make sure that the input list contains at least num occurrences of the needed elements, that is, the appropriate indexes should be tracked and as soon as the num elements is detected, the elements at these indexes are removed:
public static void removeNFirst(ArrayList<Integer> list, int num, int element) {
int[] indexes = IntStream.range(0, list.size())
.filter(i -> list.get(i) == element)
.limit(num)
.toArray();
// make sure at least num elements are found
if (indexes.length < num) {
return;
}
for (int i = indexes.length; i-- > 0; ) {
list.remove(indexes[i]);
}
}
Test:
ArrayList<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 1, 2, 1, 3));
System.out.println("Initial: " + list);
removeNFirst(list, 3, 1);
System.out.println("Removed three first 1: " + list);
removeNFirst(list, 2, 2);
System.out.println("Removed two first 2: " + list);
Output:
Initial: [1, 2, 1, 2, 1, 3]
Removed three first 1: [2, 2, 3]
Removed two first 2: [3]
SHORT ANSWER TO YOUR QUESTION:
You can keep on reducing the number till it reaches 0. If the number matches the element, then you can remove it.
QUESTION THAT NEEDS TO BE THOUGHT UPON:
What to do in case the number of elements to be removed are more than those present in the list .
for example in case of your array, what if it had been element 1 to be removed more than 4 times.
SAMPLE SOLUTION:
The logic i'm providing below works for the case when the number of elements to be removed are always less than or equal to the elements present in the list.
public class Swtich {
public static void main(String[] args) {
remove(2,1);
}
public static void remove(int num, int element) {
ArrayList<Integer> arr = new ArrayList<>();
arr.add(1);
arr.add(2);
arr.add(1);
arr.add(2);
arr.add(1);
System.out.println(arr);
int i = 0;
while (num > 0) {
// System.out.println(arr);
if (arr.get(i) == element) {
arr.remove(i);
num--;
} else {
i++;
}
}
System.out.println(arr);
}
}
and the output is as follows :
[1, 2, 1, 2, 1]
[2, 2, 1]
public static void remove(ArrayList arr, int num, int element){
int removeCounter = 0;
while (removeCounter != num) {
arr.remove(arr.indexOf(element));
removeCounter++;
}
You can use a counter like in my code... Also you should create ArrayList outside of the method block so you can print it in main method.
Combine an iterator with an counter.
public void remove(int num, int element) {
ArrayList<Integer> arr = [1, 2, 1, 2, 1];
Iterator<Integer> arrIterator = arr.iterator();
int count = 0;
while(arrIterator.hasNext() && num > count) {
if (arrIterator.next().equals(element)) {
arrIterator.remove();
count++;
}
}
}
Call remove(Object), which removes the first instance found, n times:
Integer numberToRemove = 1; // note: must be Integer
for (int i = 0; i < n; i++) {
arr.remove(numberToRemove);
}
Note that for List<Integer>, you must remove an Integer, otherwise the remove(int)` method will be called which removes the element at position, rather than by value.
I want to duplicate the elements in a linked list. This is what I have tried:
public class duplicate {
public static void main(String[] args) {
LinkedList <Integer> list = new LinkedList<Integer>() ;
list.add(2);
list.add(3);
list.add(4);
list.add(1);
list.add(0);
for( int i= 0 ; i<list.size(); i++) {
list.addAll(list);
System.out.println(list);
break;
}
}
}
But I got an infinite loop.
Firstly, your code runs just fine (the break prevents the infinite loop, see JLS-The break Statement).
Now, you don't need to for-loop over the list because List.addAll already
Appends all of the elements in the specified collection to the end of
this list, in the order that they are returned by the specified
collection's iterator (optional operation) (...)
So, just by doing this you're fine:
LinkedList <Integer> list = new LinkedList<Integer>() ;
//... code omitted (adds every number)
list.addAll(list);
However, if you want to use List.add instead of List.addAll you can do it like this (need to use for-loop):
LinkedList <Integer> list = new LinkedList<Integer>() ;
//... code omitted (adds every number)
int initialSize = list.size();
for( int i = 0 ; i < initialSize; i++) {
list.add(list.get(i));
}
System.out.println(list);
you are adding the list elements again and again in the for loop.
for(int i= 0 ; i < list.size(); i++) {
list.addAll(list);
System.out.println(list);
}
Every time it will grow & which leads the size to grow for each iteration. correct the step. Either use a local variable to store the size or change your logic
You can simply do list.addAll(list);.
If you want to use the add method as an exercise, you need to be careful to save the original size of the list before you start iterating. You can do it in the initialization part of your for loop:
public static void main(String[] args) {
List<Integer> list = new ArrayList<>(Arrays.asList(2, 3, 4, 1, 0));
for (int i = 0, size = list.size(); i < size; i++)
list.add(list.get(i));
System.out.println(list);
assert list.equals(Arrays.asList(2, 3, 4, 1, 0, 2, 3, 4, 1, 0));
}
Now you'll notice the above uses ArrayList, rather than LinkedList. In general, you should prefer ArrayList. Even the author of Java's LinkedList says he doesn't use it. See also this SO question about ArrayList vs LinkedList.
If you have to use LinkedList, you can just replace the second line from the above to this:
List<Integer> list = new LinkedList<>(Arrays.asList(2, 3, 4, 1, 0));
The rest of the code can remain unchanged. However, if you have a very long list, then using the get(index) method of the LinkedList class can reduce performance. With LinkedList, you get higher performance if you iterate (using LinkedList.iterator() or an enhanced for loop, than by using a plain for loop with get() calls. But you can't iterate over the list while adding to it, as you'll then get a ConcurrentModificationException. Instead, you can copy the linked list to an array and iterate over that, while adding to the list:
public static void main(String[] args) {
List<Integer> list = new LinkedList<>(Arrays.asList(2, 3, 4, 1, 0));
for (Integer element : list.toArray(new Integer[0])) {
list.add(element);
}
System.out.println(list);
assert list.equals(Arrays.asList(2, 3, 4, 1, 0, 2, 3, 4, 1, 0));
}
I have a pool of options in groups and I'm trying to dynamically generate the combinations for testing purposes. I would like to define the buckets and have code generating all the combinations to be fed to my TestNG test via #DataProvider. Right now I have some cases hardcoded but it's obvious is not the best way of doing it for maintaining the code.
I'm struggling to handle the case where you have x "balls" in y "buckets" when y is > 2.
In the trivial case let's say you have the following example:
public static void main(String [] args){
Object[][] combinations = getCombinations(
new String[]
{
"1", "2"
},
new String[]
{
"3", "4"
}/*,
new String[]
{
"5", "6"
}*/);
for (Object[] combination : combinations)
{
System.out.println(Arrays.toString(combination));
}
}
private Object[][] getCombinations(Object[]... arrays)
{
if (arrays.length == 0)
{
return new Object[0][0];
}
List<Object[]> solutions = new ArrayList<>();
Object[] array1 = arrays[0];
for (Object o : array1)
{
for (int i = 1; i < arrays.length; i++)
{
for (Object o2 : arrays[i])
{
int count = 0;
Object[] path = new Object[arrays.length];
path[count++] = o;
path[count++] = o2;
solutions.add(path);
}
}
}
return solutions.toArray(new Object[0][0]);
}
Output:
[1, 3]
[1, 4]
[2, 3]
[2, 4]
Adding the third "bucket" throws everything out the window.
The solutions would be as follows:
[1,3,5]
[1,3,6]
[1,4,5]
[1,4,6]
[2,3,5]
[2,3,6]
[2,4,5]
[2,4,6]
Any ideas how to attack this issue? Ideally you would pass getCombinations the amount of picks per bucket.
Although a solution code would be welcomed, I'm more interested in the reasoning behind it.
Update
For future visitors here's the great answer by Kevin Anderson in a generic form:
Unit Test:
import static org.testng.Assert.assertEquals;
import java.util.Arrays;
import java.util.List;
import org.testng.annotations.Test;
public class CombinationNGTest
{
#Test
public void testCombinaitonOnePick()
{
List<List<Integer>> result
= Combination.pickKfromEach((List<List<Integer>>) Arrays.asList(
Arrays.asList(1, 2),
Arrays.asList(3, 4)),
1);
assertEquals(result.size(), 4, result.toString());
result = Combination.pickKfromEach((List<List<Integer>>) Arrays.asList(
Arrays.asList(1, 2),
Arrays.asList(3, 4),
Arrays.asList(5, 6)),
1);
assertEquals(result.size(), 8, result.toString());
result = Combination.pickKfromEach((List<List<Integer>>) Arrays.asList(
Arrays.asList(1, 2),
Arrays.asList(3, 4),
Arrays.asList(5, 6),
Arrays.asList(7, 8)),
1);
assertEquals(result.size(), 16, result.toString());
List<List<String>> result2= Combination.pickKfromEach((List<List<String>>) Arrays.asList(
Arrays.asList("A", "B"),
Arrays.asList("C", "D")),
1);
assertEquals(result2.size(), 4, result.toString());
}
#Test
public void testCombinaitonMultiplePicks()
{
List<List<Integer>> result
= Combination.pickKfromEach((List<List<Integer>>) Arrays.asList(
Arrays.asList(1, 2, 3),
Arrays.asList(4, 5, 6)),
2);
assertEquals(result.size(), 9, result.toString());
}
}
You've hit on an overly complicated solution which, nonetheless, just happens to work for the case of two buckets. However, as you have discovered, it won't extend naturally to three or more buckets.
Here's a simpler solution for the two-bucket case, generified and using Lists in place of arrays:
// Find all 2-item combinations consisting of 1 item picked from
// each of 2 buckets
static <T> List<List<T>> pick1From2(List<List<T>> in)
{
List<List<T>> result = new ArrayList<>();
for (int i = 0; i < in.get(0).size(); ++i) {
for (int j = 0; j < in.get(1).size(); ++j) {
result.add(Arrays.asList(in.get(0).get(i), in.get(1).get(j)));
}
}
return result;
}
The outer loop runs over all the elements of the first bucket and for each element of the first bucket, the inner loop runs over the elements of the second bucket.
For three buckets, you can just add a third level of loop nesting:
// Find all 3-item combinations consisting of 1 item picked from
// each of 3 buckets
static <T> List<List<T>> pick1From3(List<List<T>> in)
{
List<List<T>> result = new ArrayList<>();
for (int i = 0; i < in.get(0).size(); ++i) {
for (int j = 0; j < in.get(1).size(); ++j) {
for (int k = 0; k < in.get(2).size(); ++k)
result.add(Arrays.asList(in.get(0).get(i), in.get(1).get(j), in.get(2).get(k)));
}
}
return result;
}
Now you have the outer loop stepping through the items of the first bucket, an intermediate loop stepping through the items of the second bucket, and an innermost loop stepping over the elements of the third bucket.
But this approach is limited by the fact that the depth of loop nesting needed is directly related to the number of buckets to be processed: Sure, you can add a fourth, a fifth, etc., level of loop nesting to handle four, five, or more buckets. However, the basic problem remains: you have to keep modifying the code to accommodate ever-increasing numbers of buckets.
The solution to the dilemma is a single algorithm which accommodate any number, N, of buckets by effectively simulating for loops nested to N levels. An array of N indices will take the place of the N loop control variables of N nested for statements:
// Find all `N`-item combinations consisting 1 item picked from
// each of an `N` buckets
static <T> List<List<T>> pick1fromN(List<List<T>> s)
{
List<List<T>> result = new ArrayList<>();
int[] idx = new int[s.size()];
while (idx[0] < s.get(0).size()) {
List<T> pick = new ArrayList(s.size());
for (int i = 0; i < idx.length; ++i) {
pick.add(s.get(i).get(idx[i]));
}
result.add(pick);
int i = idx.length - 1;
while (++idx[i] >= s.get(i).size() && i > 0) {
idx[i] = 0;
--i;
}
}
return result;
}
The indices all start off at zero, and each maxxes out upon reaching the size of the corresponding bucket. To step to the next combination (inner while loop) the last index index is incremented; if it has maxxed out, it is reset to zero and the next higher index is incremented. If the next higher index also maxes out, it resets and causes the next index to increment, and so on. idx[0] never resets after it increments, so that the outer while can detect when idx[0] has maxxed out.
Picking k items from each bucket is basically the same process, except with the sets of k-combinations of the buckets substituted for the original buckets:
// Find all `N * k`-item combinations formed by picking `k` items
// from each of `N` buckets
static <T> List<List<T>> pickKfromEach(List<List<T>> sets, int k)
{
List<List<List<T>>> kCombos = new ArrayList<>(sets.size());
for (List<T> ms : sets) {
kCombos.add(combinations(ms, k));
}
ArrayList<List<T>> result = new ArrayList<>();
int[] indices = new int[kCombos.size()];
while (indices[0] < kCombos.get(0).size()) {
List<T> pick = new ArrayList<>(kCombos.size());
for (int i = 0; i < indices.length; ++i) {
pick.addAll(kCombos.get(i).get(indices[i]));
}
result.add(pick);
int i = indices.length - 1;
while (++indices[i] >= kCombos.get(i).size() && i > 0) {
indices[i] = 0;
--i;
}
}
return result;
}
static <T> List<List<T>> combinations(List<T> s, int k) throws IllegalArgumentException
{
if (k < 0 || k > s.size()) {
throw new IllegalArgumentException("Can't pick " + k
+ " from set of size " + s.size());
}
List<List<T>> res = new LinkedList<>();
if (k > 0) {
int idx[] = new int[k];
for (int ix = 0; ix < idx.length; ++ix) {
idx[ix] = ix;
}
while (idx[0] <= s.size() - k) {
List<T> combo = new ArrayList<>(k);
for (int ix = 0; ix < idx.length; ++ix) {
combo.add(s.get(idx[ix]));
}
res.add(combo);
int ix = idx.length - 1;
while (ix > 0 && (idx[ix] == s.size() - k + ix))
--ix;
++idx[ix];
while (++ix < idx.length)
idx[ix] = idx[ix-1]+1;
}
}
return res;
}
Like the pick routine, the combinations method uses an array of indices to enumerate the combinations. But the indices are managed a bit differently. The indices start out at {0, 1, 2, ..., k-1_}, and they max-out when they have reached the values {n - k, n - k + 1, ..., n}. To step to the next combination, last index which has not yet maxed-out is incremented, and then each following index is reset to the value of the one above it, plus one.
The Problem you are struggling with can not easily be solved iteratively, since the complexity changes with the amount of given Arrays.
A solution to this problem is the use of a recursive function that generates the Permutations of the first Argument and all the following Arrays.
Unfortunately i can't write any fully working code right now, but i can try to give you an example:
public static Object[] permuteAll(Object[] objs1, Object[][] objs2) {
if(objs2.length == 1){
return permuteAll(objs1, objs2);
}else{
return permuteAll(objs2[0], objs2[/*The rest of the objs[][]*/]]);
}
}
public static Object[] permuteAll(Object[] objs1, Object[] objs2) {
return ... //Your Code for 2 buckets goes here
}
I would also recommend using Generics instead of the Object class, but depending on the way you combine your objects you might not get any real benefit out of this...
I have a list of integer arrays. I need to find the common elements between those. What I can think of is an extension of what is listed in Common elements in two lists
Example would be
[1,3,5],
[1,6,7,9,3],
[1,3,10,11]
should result in [1,3]
There are no duplicates in the arrays as well.
Is there a straight forward way to do this?
You can transform the lists to sets, and then use Set.retainAll method for intersection between the different sets.
Once you intersect all sets, you are left with the common elements, and you can transform the resulting set back to a list.
You can use Set's intersection method offered by Guava, Here is a little example :
public <T> Set<T> intersection(List<T>... list) {
Set<T> result = Sets.newHashSet(list[0]);
for (List<T> numbers : list) {
result = Sets.intersection(result, Sets.newHashSet(numbers));
}
return result;
}
Hope that could help you
We can use retainAll method of Collections. I initialised my commons arraylist with the first array list and called this for each remaining arraylists.
List<List<Integer>> lists = new ArrayList<List<Integer>>();
lists.add(new ArrayList<Integer>(Arrays.asList(1, 3, 5)));
lists.add(new ArrayList<Integer>(Arrays.asList(1, 6, 7, 9, 3)));
lists.add(new ArrayList<Integer>(Arrays.asList(1, 3, 10, 11)));
List<Integer> commons = new ArrayList<Integer>();
commons.addAll(lists.get(1));
for (ListIterator<List<Integer>> iter = lists.listIterator(1); iter.hasNext(); ) {
commons.retainAll(iter.next());
}
System.out.println(commons);
System.out.println(lists.get(1));
with Java 8
ArrayList retain = list1.stream()
.filter(list2::contains).filter(list3::contains).collect(toList())
If you are looking for a function that returns elements that exist in all lists,
then the straight forward & simple way is building a statistic { < member, occurences > }
The condition here is no duplicates among the same list,
private Set<Integer> getCommonElements(ArrayList<Integer[]> idList)
{
MapList<Integer,Short> stat = new MapList<Integer,Short>();
// Here we count how many times each value occur
for (int i = 0; i < idList.size(); i++)
{
for (int j = 0; j < idList.get(i).size; j++)
{
if (stat.containsKey(idList.get(i)[j]))
{
stat.set(idList.get(i)[j], stat.get(idList.get(i)[j])+1);
}
else
{
stat.add(idList.get(i)[j], 1);
}
}
}
// Here we only keep value that occured in all lists
for (int i = 0; i < stat.size(); i++)
{
if (stat.get(i) < idList.size())
{
stat.remove(i);
i--;
}
}
return stat.keySet();
}
public class ArrayListImpl{
public static void main(String s[]){
ArrayList<Integer> al1=new ArrayList<Integer>();
al1.add(21);al1.add(23);al1.add(25);al1.add(26);
ArrayList<Integer> al2=new ArrayList<Integer>();
al2.add(15);al2.add(16);al2.add(23);al2.add(25);
ArrayList Al3=new ArrayList<Integer>();
al3.addAll(al1);
System.out.println("Al3 Elements :"+al3);
al3.retainAll(al2); //Keeps common elements of (al1 & al2) & removes remaining elements
System.out.println("Common Elements Between Two Array List:"+al3);
}
}
If you are using JAVA 8 streams. Then using stream reduce operation we can achieve the same.
Considering your example: Let's say
a = [1,3,5], b = [1,6,7,9,3] and c = [1,3,10,11]
List<Integer> commonElements = Stream.of(a,b,c)
.reduce((s1,s2) -> {
s1.retainAll(s2);
return s1;
}).orElse(Collections.emptyList());
Keep in mind that after running this operation a will get modified with common values as well. So you will lose the actual value of a.
So elements of a and the result elements of commonElements will be essentially the same after running this operation.
Giving some another alternative code using retainAll capability of Set
public List getCommonItems(List... lists) {
Set<Integer> result = new HashSet<>(lists[0]);
for (List list : lists) {
result.retainAll(new HashSet<>(list));
}
return new ArrayList<>(result);;
}
Usage:
List list1 = [1, 2, 3]
List list2 = [3, 2, 1]
List list3 = [2, 5, 1]
List commonItems = getCommonItems(list1, list2, list3)
System.out.println("Common items: " + result);
Result:
commonItems: [1, 2]
public class commonvalue {
Public static void MyMethod(){
Set<integer> S1 = new set<integer>{1,3,5};
Set<integer> S2 = new set<integer>{1,6,7,9,3};
Set<integer> S3 = new set<integer>{1,3,10,11};
s2.retainall(s1);
s3.retainall(s2);
system.debug(s3);
}
}
I'm writing this function which I want to print all the sublists of a given list with integers. The sum of these integers should be equal to a given number n. There is also a help variable i which starts with value 0. Both the list and each sublist are an ArrayList. So the method looks like this right now:
public static void printSublists(ArrayList numbers, ArrayList sublist, int n,
int i) {
if (sublist.sum() == n) {
System.out.println(sublist.toString());
}
else {
for (int j = 0; j < numbers.size(); j++) {
sublist.add(numbers.get(i));
printSublists(numbers, sublist, n, i + 1);
sublist.remove(numbers.get(i));
}
}
}
Of course I already have the method sum(). The method does this now:
Lets say numbers = [1, 3 , 4] and n == 4, then the method should print [4] and [1 ,3], but it only prints [1, 3] ? I think the for-loop has to do the trick right? I would appreciate it if someone puts me on the right track.
update:
the values I'm giving to the method:
numbers = [1, 3, 4]
n = 4
i = 0
sublist = []
UPDATE 2:
I forgot to say that I want it to be recursive :)
Recursion stops when you see the first sublist with a sum of n. The problem is not (only) the loop but the exit criteria. Your recursive function should stop when the sublist length is 0.
Here I just wrote a working, recursive solution for your problem. It is different but I wasn't able to fix yours. While you start with an empty sublist, I chose to init the recursion with the full list an divide it into smaller sublists. This creates a tree like structure:
[1234]
[123] [234]
[12] [23] [34]
[1][2] [3] [4]
We see immediately, that we have to walk down "right" until we reach the first leaf (1), then we only walk "left". This way we visit all sublists only once.
Here's the idea written in Java:
public static void main (String[] args) {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(3);
list.add(4);
list.add(0);
printSublists(list, list, 4, true, 0);
}
public static void printSublists(List<Integer> numbers, List<Integer> sublist, int n, boolean walkRight, int level) {
// the test
if (sum(sublist) == n)
System.out.println(sublist);
// the exit criteia (leaf reached)
if (sublist.size() == 1)
return;
// visit the right sublist
if (walkRight)
printSublists(numbers, sublist.subList(0, sublist.size()-1), n, walkRight, level+1);
// we only walk the right path once
walkRight = false;
// visit the left sublist
printSublists(numbers, sublist.subList(1, sublist.size()), n, walkRight, level+1);
}
And that's the output:
[1, 3]
[4]
[4, 0]
#Test
public void test() {
printSublists(new HashSet<Integer>(Arrays.asList(2, 3, 4, 1, 2)), new HashSet<Integer>(), 4);
}
private void printSublists(Set<Integer> numbers, Set<Integer> subList, int expected) {
for (Integer element : numbers) {
subList.add(element);
if (sum(subList) == expected) {
System.out.println("result =" + subList);
}
Set<Integer> listWithoutElement = withoutElement(numbers, element);
printSublists(listWithoutElement, subList, expected);
subList.remove(element);
}
}
private Set<Integer> withoutElement(Set<Integer> numbers, Integer element) {
Set<Integer> newList = new HashSet<Integer>(numbers);
newList.remove(element);
return newList;
}
private int sum(Collection<Integer> sublist) {
int sum = 0;
for (Integer e : sublist) {
sum += e;
}
return sum;
}
Here is your solution. This problem should be for sets, not for list.
If you have set [2,3,4,1,2] the solution should be [3,1] [4] [2,2]. Then the problem has to be recursive. You have to remove duplication of course :)
In your code's for loop:
for (int j = 0; j < numbers.size(); j++) {
sublist.add(numbers.get(i));
printSublists(numbers, sublist, n, i + 1);
sublist.remove(numbers.get(i));
}
The variable j is never used. So you're doing exactly the same thing repeatedly, which I seriously doubt is what you want to do.
probably u will need to do something this way -
public static void printSublists(ArrayList numbers, ArrayList sublist, int n,
int i) {
if (sublist.sum() == n) {
System.out.println(sublist.toString());
sublist.removeAll(sublist);//added remove all here
}
else {
//for (int j = 0; j < numbers.size(); j++) {//commented this line
while(i<number.size()){//need while loop
sublist.add(numbers.get(i));
printSublists(numbers, sublist, n, ++i);//i+1 changed to ++i
//sublist.remove(numbers.get(i));// commented here
}
}
}