Remove sublists from list while iterating - java

I want to count number of elements and remove some if they meet a criterion. Removing using collect and removeAll doesn't work since it removes all equal elements and I want to remove a range not all.
I tried to use sublist.clear() but I get ConcurrentModificationException even though I'm using it.remove().
public static List<Integer> controlOccurrences(List<Integer> sortedArr, int m) {
int writelndex = 0, count=1;
List<List<Integer>> toRemove = new ArrayList<>();
for (int i = 1; i < sortedArr.size(); ++i) {
if (sortedArr.get(i-1).equals(sortedArr.get(i))) {
count++;
} else {
if(count == m) {
int nCopies = Math.min(2,m);
List<Integer> c = sortedArr.subList(writelndex + nCopies, i);
toRemove.add(c);
}
count = 1;
writelndex = i;
}
}
Iterator<List<Integer>> iterator = toRemove.iterator();
while (iterator.hasNext()) {
List<Integer> integers = iterator.next();
iterator.remove();
integers.clear();
}
return sortedArr;
}
EDIT: adding an example:
Lets say we have the following list: (1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5) and m = 3. This means that all numbers that occur m times should occur 2 times (Math.min(2,3)). So the expected result is (1, 2, 2, 2, 2, 3, 3, 4, 4, 5, 5).
EDIT 2: #ShubhenduPramanik Solved the task very elegantly.
However, it's still unclear to me why ConcurrentModificationException was thrown even though I was using iterator.remove() and how would you go about removing a sublist from a list while iterating over it.

Hope this helps:
static List<Integer> controlOccurrences(List<Integer> sortedArr, int m) {
//make the count of each element
Map<Integer, Long> result = sortedArr.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
for (Map.Entry<Integer, Long> entry : result.entrySet()) {
if (entry.getValue() == m) {
// Here 2 is hard coded. You can make a variable and pass it to the method with a parameter
for (int i = 0; i < m - 2; i++)
{
sortedArr.remove(entry.getKey());
}
}
}
return sortedArr;
}
N.B: This code is not perfect as I've assumed that m>=2

If I correctly understood the task then the algorithm:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) throws IOException {
int m = 3;
BufferedReader reader = new BufferedReader(
new InputStreamReader(System.in));
int numbers;
List<Integer> sortedList = new ArrayList<>();
// Fill in the list with values
for (int i = 0; i < 13; i++) {
numbers = Integer.parseInt(reader.readLine());
sortedList.add(numbers);
}
System.out.println(controlOccurrences(sortedList, m));
}
public static List<Integer> controlOccurrences(List<Integer> sortedArr, int m) {
int count= 1;
for (int i = 0; i < sortedArr.size(); i++) {
for (int j = 0; j < sortedArr.size(); j++) {
if (sortedArr.get(i).equals(sortedArr.get(j)) && i != j) {
count += 1;
}
}
if (count == m) {
sortedArr.remove(i);
count = 1;
} else {
count = 1;
}
}
return sortedArr;
}
}

To get the most optimized solution, you should:
1. Build a list (or set) of the indices of the values to remove
2. Move values of your original list to a new one, except the one at the listed indices.
3. Return the new list.
This way, your algorithm complexity is O(2n), which is more optimized than both previous answers. Plus, you keep given list untouched (which can be recommended according to your execution context). Last advantage, the copy is favored because each remove call on a list is potentially heavy (inner objects after removed index are moved to the left: partial hidden browsing -_- )
I won't directly give you a working code, to let you practice ;).
Note: your use-case is too complex for it, but you should look at List.removeIf() code of array list API, which is really well optimized. Here is an article talking about it: advantages of removeIf method

Related

In Java code i the method i created only put the first duplicate instance to a new array

I want to remove the duplicates by putting them in a new array but somehow I only get a first instance and a bunch of zeros.
Here is my code:
public class JavaApplication7 {
public static void main(String[] args) {
int[] arr = new int[] {1,1,2,2,2,2,3,4,5,6,7,8};
int[] res = removeD(arr);
for (int i = 0; i < res.length; i++) {
System.out.print(res[i] + " ");
}
}
public static int[] removeD(int[] ar) {
int[] tempa = new int[ar.length];
for (int i = 0; i < ar.length; i++) {
if (ar[i] == ar[i+1]) {
tempa[i] = ar[i];
return tempa;
}
}
return null;
}
}
expected: 1,2
result: 1,0,0,0,0,0,0....
why dont you make use of HashSet?
final int[] arr = new int[] { 1, 1, 2, 2, 2, 2, 3, 4, 5, 6, 7, 8 };
final Set<Integer> set = new HashSet<>();
for (final int i : arr) {
// makes use of Integer's hashCode() and equals()
set.add(Integer.valueOf(i));
}
// primitive int array without zeros
final int[] newIntArray = new int[set.size()];
int counter = 0;
final Iterator<Integer> iterator = set.iterator();
while (iterator.hasNext()) {
newIntArray[counter] = iterator.next().intValue();
counter++;
}
for (final int i : newIntArray) {
System.out.println(i);
}
Edit
if you want your array to be ordered
final int[] arr = new int[] { 9, 9, 8, 8, 1, 1, 2, 2, 2, 2, 3, 4, 5, 6, 7, 8 };
Set<Integer> set = new HashSet<>();
for (final int i : arr) {
// makes use of Integer's hashCode() and equals()
set.add(Integer.valueOf(i));
}
// priomitive int array without zeros
final int[] newIntArray = new int[set.size()];
int counter = 0;
// SetUtils.orderedSet(set) requires apache commons collections
set = SetUtils.orderedSet(set);
final Iterator<Integer> iterator = set.iterator();
while (iterator.hasNext()) {
newIntArray[counter] = iterator.next().intValue();
counter++;
}
for (final int i : newIntArray) {
System.out.println(i);
}
A couple of points to help you:
1) With this: for(int i =0; i<ar.length; i++){ - you will get an IndexOutOfBoundsException because you are checking [i+1]. Hint: it is only the last element that will cause this...
2) Because you're initialising the second array with the length of the original array, every non-duplicate will be a 0 in it, as each element is initialised with a 0 by default. So perhaps you need to find how many duplicates there are first, before setting the size.
3) As mentioned in the comments, you are returning the array once the first duplicate is found, so remove that and just return the array at the end of the method.
4) You will also get multiple 2s because when you check i with i+1, it will find 3 2s and update tempa with each of them, so you'll need to consider how to not to include duplicates you've already found - based on your expected result.
These points should help you get the result you desire - if I (or someone else) just handed you the answer, you wouldn't learn as much as if you researched it yourself.
Here:
int[] tempa = new int[ar.length];
That creates a new array with the same size as the incoming one. All slots in that array are initialized with 0s!
When you then put some non-0 values into the first slots, sure, those stick, but so do the 0s in all the later slots that you don't "touch".
Thus: you either have to use a data structure where you can dynamically add new elements (like List/ArrayList), or you have to first iterate the input array to determine the exact count of objects you need, to then create an appropriately sized array, to then fill that array.
Return statement
As both commenters said, you return from the method as soon as you find your first duplicate. To resolve that issue, move the return to the end of the method.
Index problems
You will then run into another issue, an ArrayIndexOutOfBoundsException because when you are checking your last item (i = ar.length - 1) which in your example would be 11 you are then comparing if ar[11] == ar[12] but ar has size 12 so index 12 is out of the bounds of the array. You could solve that by changing your exit condition of the for loop to i < ar.length - 1.
Zeros
The zeros in your current output come from the initialization. You initialize your tempa with int[ar.length] this means in the memory it will reserve space for 12 ints which are initialized with zero. You will have the same problem after resolving both issues above. Your output would look like this: 1 0 2 2 2 0 0 0 0 0 0 0. This is because you use the same index for tempa and ar. You could solve that problem in different ways. Using a List, Filtering the array afterwards, etc. It depends what you want to do exactly.
The code below has the two first issues solved:
public class JavaApplication7 {
public static void main(String[] args) {
int[] arr = new int[] { 1, 1, 2, 2, 2, 2, 3, 4, 5, 6, 7, 8 };
int[] res = removeD(arr);
for (int i = 0; i < res.length; i++) {
System.out.print(res[i] + " ");
}
}
public static int[] removeD(int[] ar) {
int[] tempa = new int[ar.length];
for (int i = 0; i < ar.length - 1; i++) {
if (ar[i] == ar[i + 1]) {
tempa[i] = ar[i];
}
}
return tempa;
}
}
There were a some error mentioned already:
return exits the method.
with arr[i+1] the for condition should bei+1 < arr.length`.
the resulting array may be smaller.
So:
public static int[] removeD(int[] ar) {
// Arrays.sort(ar);
int uniqueCount = 0;
for (int i = 0; i < ar.length; ++i) {
if (i == 0 || ar[i] != ar[i - 1]) {
++uniqueCount;
}
}
int[] uniques = new int[uniqueCount];
int uniqueI = 0;
for (int i = 0; i < ar.length; ++i) {
if (i == 0 || ar[i] != ar[i - 1]) {
uniques[uniqueI] = arr[i];
++uniqueI;
}
}
return uniques;
}

How to get all possible combinations from two arrays?

I have the two arrays:
String[] operators = {"+", "-", "*"};
int[] numbers = {48, 24, 12, 6};
And I want to get all possible combination in a String format like this:
48+24+12+6
48+24+12-6
48+24+12*6
48+24-12+6
48+24-12-6
48+24-12*6
..........
48*24*12*6
This what I have tried:
for (int i = 0; i < operators.length; i++) {
System.out.println(numbers[0] + operators[i] + numbers[1] +
operators[i] + numbers[2] + operators[i] + numbers[3]);
}
But it only prints:
48+24+12+6
48-24-12-6
48*24*12*6
How to solve this?
This is not a duplicate because I don't want to get every two pairs of data, I want to get every combination in 4 pairs. The duplicate is different.
Use a triple loop:
for (int i=0; i < operators.length; ++i) {
for (int j=0; j < operators.length; ++j) {
for (int k=0; k < operators.length; ++k) {
System.out.println(numbers[0] + operators[i] + numbers[1] + operators[j] +
numbers[2] + operators[k] + numbers[3]);
}
}
}
You essentially want to take the cross product of the operators vector (if it were a vector). In Java, this translates to a triply-nested set of loops.
While #TimBiegeleisen solution would work like a charm, its complexity might be an issue. The better approach would be a code like this:
static void combinationUtil(
int[] arr, int n, int r, int index, int[] data, int i) {
// Current combination is ready to be printed, print it
if (index == r) {
for (int j = 0; j < r; j++)
System.out.print(data[j] + " ");
System.out.println("");
return;
}
// When no more elements are there to put in data[]
if (i >= n)
return;
// current is included, put next at next location
data[index] = arr[i];
combinationUtil(arr, n, r, index + 1, data, i + 1);
// current is excluded, replace it with next (Note that
// i+1 is passed, but index is not changed)
combinationUtil(arr, n, r, index, data, i + 1);
}
// The main function that prints all combinations of size r
// in arr[] of size n. This function mainly uses combinationUtil()
static void printCombination(int arr[], int n, int r) {
// A temporary array to store all combination one by one
int data[] = new int[r];
// Print all combination using temprary array 'data[]'
combinationUtil(arr, n, r, 0, data, 0);
}
Source: GeeksForGeeks and my IDE :)
This sounds like a textbook case for a recursive solution:
public static void combineAndPrint(String[] pieces, String[] operators) {
if (pieces.length < 1) {
// no pieces? do nothing!
} else if (pieces.length == 1) {
// just one piece? no need to join anything, just print it!
System.out.println(pieces[0]);
} else {
// make a new array that's one piece shorter
String[] newPieces = new String[pieces.length - 1];
// copy all but the first two pieces into it
for (int i = 2; i < pieces.length; i++) {
newPieces[i - 1] = pieces[i];
}
// combine the first two pieces and recurse
for (int i = 0; i < operators.length; i++) {
newPieces[0] = pieces[0] + operators[i] + pieces[1];
combineAndPrint(newPieces, operators);
}
}
}
public static void main(String[] args) {
String[] operators = {"+", "-", "*"};
String[] numbers = {"48", "24", "12", "6"};
combineAndPrint(numbers, operators);
}
Try it online!
BTW, to generalize this method so that you can do more things with the generated expressions than just printing them, I would recommend making it accept an extra Consumer<String> parameter. That is, you could rewrite the method declaration as:
public static void combine(String[] pieces, String[] operators, Consumer<String> consumer) {
and replace the System.out.println(pieces[0]) with consumer.accept(pieces[0]) and the recursive call to combineAndPrint(newPieces, operators) with combine(newPieces, operators, consumer). Then just call it from your main method e.g. as:
combine(numbers, operators, s -> System.out.println(s));
Try it online!
(Of course, doing it in this more flexible way requires a somewhat modern Java version — Java 8 or later, to be specific — whereas the first example I showed above should work on even ancient versions all the way down to Java 1.0. Maybe in some future version of Java we'll get proper support for coroutines and generators, like Python and Kotlin and even modern JS already have, and then we won't even need to pass the consumer around any more.)
As already pointed out by findusl in his answer, the problem here is, strictly speaking, not to find any sort of "combination of two arrays". Instead, you basically just want to find all possible combinations of the available operators.
(The fact that you later want to "interveave" them with operands is rather unrelated to the core of the question)
So here is another option for solving this: You can create an iterable over all combinations of a certain number of elements from a certain set (in your case: the operators) and then simply combine the results with the other set (in your case: the operands).
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
public class OperatorsTest {
public static void main(String[] args) {
String[] operators = {"+", "-", "*"};
int[] numbers = {48, 24, 12, 6};
CombinationIterable<String> iterable =
new CombinationIterable<String>(3, Arrays.asList(operators));
for (List<String> element : iterable) {
System.out.println(interveave(element, numbers));
}
}
private static String interveave(List<String> operators, int numbers[]) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < operators.size(); i++) {
sb.append(numbers[i]);
sb.append(operators.get(i));
}
sb.append(numbers[numbers.length - 1]);
return sb.toString();
}
}
class CombinationIterable<T> implements Iterable<List<T>> {
private final List<T> input;
private final int sampleSize;
private final int numElements;
public CombinationIterable(int sampleSize, List<T> input) {
this.sampleSize = sampleSize;
this.input = input;
numElements = (int) Math.pow(input.size(), sampleSize);
}
#Override
public Iterator<List<T>> iterator() {
return new Iterator<List<T>>() {
private int current = 0;
private final int chosen[] = new int[sampleSize];
#Override
public boolean hasNext() {
return current < numElements;
}
#Override
public List<T> next() {
if (!hasNext()) {
throw new NoSuchElementException("No more elements");
}
List<T> result = new ArrayList<T>(sampleSize);
for (int i = 0; i < sampleSize; i++) {
result.add(input.get(chosen[i]));
}
increase();
current++;
return result;
}
private void increase() {
int index = chosen.length - 1;
while (index >= 0) {
if (chosen[index] < input.size() - 1) {
chosen[index]++;
return;
}
chosen[index] = 0;
index--;
}
}
};
}
}
The task resembles that of finding a set of operations that can be done with a certain number of operands and operators, and thus, this Q/A may be related. But whether or not things like associativity or commutativity should be considered here was not mentioned in the question.
I made an alternative, overengineered (but flexible!) "business" solution. The array lengths and values (numbers and operators) can be flexible.
package test1;
import java.io.IOException;
import java.util.ArrayList;
public class MainClass {
public static void main(String[] args) throws IOException {
String[] operators = {"+", "-", "*"};
int[] numbers = {48, 24, 12, 6};
ArrayList<String> strings =
new MainClass().getAllPossibleCombinations(numbers, operators);
for (String string : strings) {
System.out.println(string);
}
}
private ArrayList<String> getAllPossibleCombinations(
int[] numbers, String[] operators) {
if (numbers.length < 2)
throw new IllegalArgumentException(
"Length of numbers-array must be at least 2");
if (operators.length < 1)
throw new IllegalArgumentException(
"Length of operators-array must be at least 1");
ArrayList<String> returnList = new ArrayList<>();
int[] indexes = new int[numbers.length - 1];
while (true) {
StringBuilder line = new StringBuilder();
for (int i = 0; i < numbers.length; i++) {
int number = numbers[i];
line.append(number);
if (i < indexes.length) {
line.append(operators[indexes[i]]);
}
}
returnList.add(line.toString());
try {
this.updateIndexes(indexes, operators.length - 1);
} catch (NoMoreCombinationsException e) {
break;
}
}
return returnList;
}
private void updateIndexes(int[] currentIndexes, int maxValue)
throws NoMoreCombinationsException {
if (this.intArrayIsOnly(currentIndexes, maxValue)) {
throw new NoMoreCombinationsException();
}
for (int i = currentIndexes.length - 1; i >= 0; i--) {
int currentIndex = currentIndexes[i];
if (currentIndex < maxValue) {
currentIndexes[i] = currentIndex + 1;
break;
} else {
currentIndexes[i] = 0;
}
}
}
private boolean intArrayIsOnly(int[] array, int value) {
for (int iteratedValue : array) {
if (iteratedValue != value) return false;
}
return true;
}
}
class NoMoreCombinationsException extends Exception {
public NoMoreCombinationsException() {
}
public NoMoreCombinationsException(String message) {
super(message);
}
public NoMoreCombinationsException(String message, Throwable cause) {
super(message, cause);
}
public NoMoreCombinationsException(Throwable cause) {
super(cause);
}
public NoMoreCombinationsException(
String message, Throwable cause,
boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
Works like a charm :)
A bit of background information why the answers are they way they are. This problem is not really called "all possible combinations" as that is usually the problem where you can represent the elements as bits and switch them to 0 or 1 whether the element is included or not. This has a complexity of 2^N where N is the amount of operators you have. This can be solved easily in a single loop.
However in your case you have the "urn problem with replacement and sequence". The complexity of this is N^n where n is the amount of spots you have to fill with operators. (This is often seen for pincodes where each spots can be 10 values). So because this is of higher complexity than the "all possible combinations" problem you need multiple loops or recursive calls.
So to answer the question, "how to solve this?". You have to solve it with multiple loops or recursion because of the underlying problem's complexity.
I've developed a class that covers this use case and many others. I call it the TallyCounter. Your question would be answered with this class like this:
package app;
import java.util.HashMap;
import java.util.Map;
import app.TallyCounter.Type;
public class App {
public static void main(String args[]) throws Exception {
Map<Long, String> map = new HashMap<>();
map.put(0l, "+");
map.put(1l, "-");
map.put(2l, "*");
TallyCounter counter = new TallyCounter(3, Type.NORMAL, 2);
do {
System.out.format("48%s24%s12%s6\n",
map.get(counter.getArray()[2]),
map.get(counter.getArray()[1]),
map.get(counter.getArray()[0])
);
counter.increment();
} while (!counter.overflowFlag);
}
}
You don't need multiple loops or recursion.
Here's an example showcasing a limited number of loops and no recursion at all.
int[][] combine(int[] values) {
int size = values.length;
int combinations = 1;
for (int i = 0; i < size; i++) {
combinations *= size;
}
// or int combinations = (int)Math.pow(size, size);
int[][] result = new int[combinations][size];
for (int i = 0; i < combinations; i++) {
int index = i;
for (int j = 0; j < size; j++) {
result[i][j] = values[index % size];
index /= size;
}
}
return result;
}
If you use it with three elements, [1, 2, 3], as in the code below:
void testCombine() {
int[][] combinations = combine(new int[]{1, 2, 3});
for (int[] combination : combinations) {
System.out.println(Arrays.toString(combination));
}
}
You end up with the following result:
[1, 1, 1]
[2, 1, 1]
[3, 1, 1]
[1, 2, 1]
[2, 2, 1]
[3, 2, 1]
[1, 3, 1]
[2, 3, 1]
[3, 3, 1]
[1, 1, 2]
[2, 1, 2]
[3, 1, 2]
[1, 2, 2]
[2, 2, 2]
[3, 2, 2]
[1, 3, 2]
[2, 3, 2]
[3, 3, 2]
[1, 1, 3]
[2, 1, 3]
[3, 1, 3]
[1, 2, 3]
[2, 2, 3]
[3, 2, 3]
[1, 3, 3]
[2, 3, 3]
[3, 3, 3]
You can use streams to get all possible combinations of two arrays. First, iterate over the numbers array and append the operator signs to each number, you get an array like this: {"48+", "48-", "48*"} for each number. The number of operators may vary. Then reduce this stream of arrays to a single array by sequentially multiplying array pairs, you get an array of possible combinations.
Try it online!
String[] operators = {"+", "-", "*"};
int[] numbers = {48, 24, 12, 6};
// an array of possible combinations
String[] comb = IntStream.range(0, numbers.length)
// append each substring with possible
// combinations, except the last one
// return Stream<String[]>
.mapToObj(i -> numbers.length - 1 > i ?
Arrays.stream(operators)
.map(op -> numbers[i] + op)
.toArray(String[]::new) :
new String[]{"" + numbers[i]})
// reduce stream of arrays to a single array
// by sequentially multiplying array pairs
.reduce((arr1, arr2) -> Arrays.stream(arr1)
.flatMap(str1 -> Arrays.stream(arr2)
.map(str2 -> str1 + str2))
.toArray(String[]::new))
.orElse(null);
// column-wise output (three columns in this case)
int columns = (int) Math.pow(operators.length, numbers.length - 2);
IntStream.range(0, columns)
.mapToObj(i -> IntStream.range(0, comb.length)
.filter(j -> j % columns == i)
.mapToObj(j -> comb[j])
.collect(Collectors.joining(" | ")))
.forEach(System.out::println);
Output:
48+24+12+6 | 48-24+12+6 | 48*24+12+6
48+24+12-6 | 48-24+12-6 | 48*24+12-6
48+24+12*6 | 48-24+12*6 | 48*24+12*6
48+24-12+6 | 48-24-12+6 | 48*24-12+6
48+24-12-6 | 48-24-12-6 | 48*24-12-6
48+24-12*6 | 48-24-12*6 | 48*24-12*6
48+24*12+6 | 48-24*12+6 | 48*24*12+6
48+24*12-6 | 48-24*12-6 | 48*24*12-6
48+24*12*6 | 48-24*12*6 | 48*24*12*6
See also: Generate all possible string combinations by replacing the hidden “#” number sign

Java: Combinations of arrays, x per array

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...

How to find duplicates in a java array?

I'm trying to count how many duplicate items are in an array.
Example:
[0, 2, 0] would return 2, [0, 0, 0] would return 3, [0, 1, 2] = 0
So far I have it working for when all three items are equal, but I'm not sure why it's returning one less than what it should for 2 items being the same.
int equal = 0;
for(int i = 0; i < recent.length; i++) {
for(int j = i; j < recent.length; j++) {
if(i != j && recent[i].equals(recent[j])) {
equal++;
}
}
}
Your algorithm is flawed in the following way: for every element in the array you look at all the elements after that element and if they happen to be equal, you increase the counter. However when you have 3 same elements, you count the last one twice - when you run internal loop for first and for second element. Moreover you never count the first element.
So it works by accident for [0, 0, 0] but doesn't work for other inputs.
I think that having nested loops is quite inefficient. You should be able to do it in o(n) rather than o(n^2).
If you time yours against the following...
public void run() {
int[] array = createRandomArray(2000000, 1000000);
System.out.println(countNumDups1(array));
}
private int[] createRandomArray(int numElements, int maxNumExclusive) {
int[] array = new int[numElements];
Random random = new Random();
for (int i = 0; i < array.length; i++) {
array[i] = random.nextInt(maxNumExclusive);
}
return array;
}
private int countNumDups1(int[] array) {
Map<Integer, Integer> numToCountMap = new HashMap<>();
for (int i = 0; i < array.length; i++) {
Integer key = array[i];
if (numToCountMap.containsKey(key)) {
numToCountMap.put(key, numToCountMap.get(key) + 1);
}
else {
numToCountMap.put(key, 1);
}
}
int numDups = 0;
for (int i = 0; i < array.length; i++) {
Integer key = array[i];
if (numToCountMap.get(key) > 1) {
numDups++;
}
}
return numDups;
}
I think you'll find the above is much faster even considering the horrible inefficiency of autoboxing and object creation.
The code you gave counts equivalences, so it adds one every time an element equals another element.
It sounds like what you want is the number of duplicate items, which is the same as (length - number of items that don't have a duplicate). I will call the latter "uniqueItems".
I would recommend the following:
// set of every item seen
Set<Integer> allItems = new HashSet<Integer>();
// set of items that don't have a duplicate
Set<Integer> uniqueItems = new HashSet<Integer>();
for(int i = 0; i < recent.length; i++) {
Integer val = i;
if(allItems.contains(val)) {
// if we've seen the value before, it is not a "uniqueItem"
uniqueItems.remove(val);
} else {
// assume the value is a "uniqueItem" until we see it again
uniqueItems.add(val);
}
allItems.add(val);
}
return recent.length - uniqueItems.size();
The below code works perfectly to find the duplicates
int array[] = {1,2,3,4,5,2,3,4,5,3,4,5,4,5,5};
HashMap<Integer,Integer> duplicates = new HashMap<Integer,Integer>();
for(int i=0; i<array.length; i++)
{
if(duplicates.containsKey(array[i]))
{
int numberOfOccurances = duplicates.get(array[i]);
duplicates.put(array[i], (numberOfOccurances + 1));
}else{
duplicates.put(array[i], 1);
}
}
Iterator<Integer> keys = duplicates.keySet().iterator();
System.out.print("Duplicates : " );
while(keys.hasNext())
{
int k = keys.next();
if(duplicates.get(k) > 1)
{
System.out.print(" "+k);
}
}
You are counting the number of pairs of indices that have equal values. What you claim to want is the total size of all sets of equal elements that have more than one element in them.
I would use a Map or similar to count the total number of appearances of a given value. At the end, iterate over the key values adding the number of appearances for each key that has more than one appearance.
int intArray[] = {5, 1, 2, 3, 4, 5, 3, 2};
String val = "";
int c = 1;
Map<Integer, Integer> nwmap = new HashMap<Integer, Integer>();
for (int i = 0; i < intArray.length; i++) {
Integer key = intArray[i];
if(nwmap.get(key) != null && nwmap.containsKey(key)){
val += " Duplicate: " +String.valueOf(key)+"\n";
}else{
nwmap.put(key, c);
c++;
}
}
LOG.debug("duplicate value:::"+val);
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
public class ArrayDuplicateCount {
/**
* #author:raviteja katari
*/
public static void main(String[] args) {
int intArray[] = {5, 1,4,4,4,5,1,2,1,2,5,5};
//for counting duplicate items
int c = 0;
//creating map collection to hold integers as keys and Cont as value
Map<Integer, Integer> nwmap = new LinkedHashMap<Integer, Integer>();
for (int i = 0; i <intArray.length; i++) {
//Assigning array element to key
Integer key = intArray[i];
//this code checks for elemnt if present updates count value else
//put the new Array elemnt into map and increment count
if(nwmap.containsKey(key)){
//updating key value by 1
nwmap.put(key, nwmap.get(key) + 1);
}else{
//Adding new array element to map and increasing count by 1
nwmap.put(key, c+1);
}
}
//printing map
System.out.println(nwmap);
}
}
output:
{5=4, 1=3, 4=3, 2=2}
public void TotalduplicateNumbers {
int a[] = {2,8,2,4,4,6,7,6,8,4,5};
Map<Integer,Integer> m = new HashMap<Integer,Integer>();
for(int i=0;i<a.length;i++){
if(!m.containsKey(a[i]))
{
m.put(a[i], 1);
}
else
{
m.put(a[i], (m.get(a[i])+1));
}
}
for(Integer i:m.keySet()){
System.out.println("Number "+i+" "+"Occours "+m.get(i)+" time,");
}
}
We have an array containing 11 numbers, The logic is to create a map using these no. in which KEYS of map would be the actual number that must be entered by user and no. of occournce of that actual no. would be the value of that KEY. Here, containsKey() method checks whether the map contain that key already and return boolean value true or false as applied.If it does not contain then add that key into the map and its corresponding value should be 1 otherwise key would have already be contained in map so get the value of that key using get() and increment it by 1. Finally printing the map.
OUTPUT:--
Number 2 Occours 2 time,
Number 4 Occours 3 time,
Number 5 Occours 1 time,
Number 6 Occours 2 time,
Number 7 Occours 1 time,
Number 8 Occours 2 time,

Eliminating Recursion

I've just been looking at the following piece of code
package test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(final String[] args) {
final int sizeA = 3;
final int sizeB = 5;
final List<int[]> combos = getAllCombinations(sizeA-1, sizeB);
int counter = 1;
for(final int[] combo : combos) {
System.out.println("Combination " + counter);
System.out.println("--------------");
for(final int value : combo) {
System.out.print(value + " ");
}
System.out.println();
System.out.println();
++counter;
}
}
private static List<int[]> getAllCombinations(final int maxIndex, final int size) {
if(maxIndex >= size)
throw new IllegalArgumentException("The maximum index must be smaller than the array size.");
final List<int[]> result = new ArrayList<int[]>();
if(maxIndex == 0) {
final int[] array = new int[size];
Arrays.fill(array, maxIndex);
result.add(array);
return result;
}
//We'll create one array for every time the maxIndex can occur while allowing
//every other index to appear, then create every variation on that array
//by having every possible head generated recursively
for(int i = 1; i < size - maxIndex + 1; ++i) {
//Generating every possible head for the array
final List<int[]> heads = getAllCombinations(maxIndex - 1, size - i);
//Combining every head with the tail
for(final int[] head : heads) {
final int[] array = new int[size];
System.arraycopy(head, 0, array, 0, head.length);
//Filling the tail of the array with i maxIndex values
for(int j = 1; j <= i; ++j)
array[size - j] = maxIndex;
result.add(array);
}
}
return result;
}
}
I'm wondering, how do I eliminate recursion from this, so that it returns a single random combination, rather than a list of all possible combinations?
Thanks
If I understand your code correctly your task is as follows: give a random combination of numbers '0' .. 'sizeA-1' of length sizeB where
the combination is sorted
each number occurs at least once
i.e. in your example e.g. [0,0,1,2,2].
If you want to have a single combination only I'd suggest another algorithm (pseudo-code):
Randomly choose the step-up positions (e.g. for sequence [0,0,1,1,2] it would be steps (1->2) & (3->4)) - we need sizeA-1 steps randomly chosen at sizeB-1 positions.
Calculate your target combination out of this vector
A quick-and-dirty implementation in java looks like follows
// Generate list 0,1,2,...,sizeB-2 of possible step-positions
List<Integer> steps = new ArrayList<Integer>();
for (int h = 0; h < sizeB-1; h++) {
steps.add(h);
}
// Randomly choose sizeA-1 elements
Collections.shuffle(steps);
steps = steps.subList(0, sizeA - 1);
Collections.sort(steps);
// Build result array
int[] result = new int[sizeB];
for (int h = 0, o = 0; h < sizeB; h++) {
result[h] = o;
if (o < steps.size() && steps.get(o) == h) {
o++;
}
}
Note: this can be optimized further - the first step generates a random permutation and later strips this down to desired size. Therefore it is just for demonstration purpose that the algorithm itself works as desired.
This appears to be homework. Without giving you code, here's an idea. Call getAllCombinations, store the result in a List, and return a value from a random index in that list. As Howard pointed out in his comment to your question, eliminating recursion, and returning a random combination are separate tasks.

Categories