Related
I am working on a sharding problem.
Imagine I have 10 lists.
Each list has a series of items that are independently sorted.
I want to get the Nth item as if all the lists were sorted together in one large list.
Do I need to sort the lists overall to get an item at a particular index?
I solved a similar but not equivalent problem where there is:
10 lists
Each list represents a range of items that are after the previous list.
here's the code to iterate through all the indexes of the lists:
/* code to iterate through all items in order
* threads refers to one of the lists */
int sizes[] = new int[threads.size()];
for (int i = 0 ; i < threads.size(); i++) {
sizes[i] = threads.get(i).data2.size();
}
int n = 0;
int thread = 0;
int size = threads.size();
int offset = 0;
long iterationStart = System.nanoTime();
while (thread < size) {
// System.out.println(String.format("%d %d", thread, offset + threads.get(thread).data.get(n)));
int current = offset + threads.get(thread).data.get(n);
n = n + 1;
if (n == sizes[thread]) {
offset += sizes[thread];
thread++;
n = 0;
}
}
long iterationEnd = System.nanoTime();
long iterationTime = iterationEnd - iterationStart;
Here's the code to lookup an item by index.
int lookupKey = 329131;
int current = lookupKey;
int currentThread = 0;
int total = 0;
while (current >= 0 && currentThread <= size - 1) {
int next = current - sizes[currentThread];
if (next >= 0) {
total += sizes[currentThread];
current -= sizes[currentThread];
currentThread++;
} else {
break;
}
}
long lookupEnd = System.nanoTime();
long lookupTime = lookupEnd - lookupStart;
System.out.println(String.format("%d %d",
currentThread,
total + threads.get(currentThread).data.get(current)));
I'm hoping there's some property of sorted collections that I can use to retrieve the Nth item in an overall sorted lists.
What I have in effect is multiple partial orders.
I have some other code that does a N way merge between multiple sorted lists. Is the fastest option to run this in a loop up to lookupIndex?
int size1 = threads.size();
int[] positions = new int[size1];
Arrays.fill(positions, 0);
PriorityQueue<Tuple> pq = new PriorityQueue<>(new Comparator<Tuple>() {
#Override
public int compare(Tuple o1, Tuple o2) {
return o1.value.compareTo(o2.value);
}
});
long startOrderedIteration = System.nanoTime();
for (ShardedTotalRandomOrder thread : threads) {
for (int i = 0; i < 10; i++) {
// System.out.println(thread.data2.get(i));
pq.add(thread.data2.get(i));
}
}
List<Integer> overall = new ArrayList<>();
while (!pq.isEmpty()) {
Tuple poll = pq.poll();
ArrayList<Tuple> data2 = threads.get(poll.thread).data2;
if (positions[poll.thread] < data2.size()) {
Tuple nextValue = data2.get(positions[poll.thread]++);
pq.offer(nextValue);
}
overall.add(poll.value);
// System.out.println(String.format("%d %d", poll.thread, poll.value));
}
System.out.println(overall);
long endOrderedIteration = System.nanoTime();
long orderedIterationTime = endOrderedIteration - startOrderedIteration;
You don't need to resort them. Since each list is already sorted you can merge them as follows. This uses a single method to merge two lists based on their relative values. Then it returns that list and feeds it back into the method to merge it with the next list.
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class Merging {
public static void main(String[] args) {
List<Integer> list1 = List.of(5,10,15,20,25,30,35,40,45,50);
List<Integer> list2 = List.of(2,4,6,8,10);
List<Integer> list3 = List.of(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
int nth = 10;
List<List<Integer>> lists = List.of(list1,list2,list3);
List<Integer> merged = lists.get(0);
for (int i = 1; i < lists.size(); i++) {
merged = mergeLists(merged, lists.get(i));
}
System.out.println(merged.get(nth));
}
prints
7
This works with any type that implements the Comparable interface.
It will loop until one list is exhausted or until both indices exceed the combined list size.
Once either list is finished, the other can be appended via the sublist.
public static <T extends Comparable<? super T>> List<T> mergeLists(List<T> list1, List<T> list2) {
List<T> merged = new ArrayList<>();
int i1 = 0;
int i2 = 0;
while (i1 + i2 < list1.size() + list2.size()) {
if (i1 >= list1.size()) {
merged.addAll(list2.subList(i2,list2.size()));
break;
}
if (i2 >= list2.size()) {
merged.addAll(list1.subList(i1,list1.size()));
break;
}
if(list1.get(i1).compareTo(list2.get(i2)) <= 0) {
merged.add(list1.get(i1++));
} else {
merged.add(list2.get(i2++));
}
}
return merged;
}
}
Here is a relatively efficient (linear with respect to the number of lists) algorithm that leverages some of the power of streams, but avoids a full list merge.
EDIT: To address shortcomings such as array length checking, array destruction, and readability I have improved this example. For better comparison, I have used the same integer test data as the other answer.
This virtual queue backed by the (presumably) immutable array will not mutate or otherwise
public class VirtualQueue<T> {
private List<T> list;
private int index=0;
public VirtualQueue(List<T> list) { this.list = list; }
public boolean hasMore() { return index < list.size(); }
public T pop() { return list.get(index++); }
public T peek() { return list.get(index);}
}
(I suspect that there is an easier way to do this with standard collections)
List<Integer> list1 = List.of(5,10,15,20,25,30,35,40,45,50);
List<Integer> list2 = List.of(2,4,6,8,10);
List<Integer> list3 = List.of(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
List<VirtualQueue<Integer>> listList = List.of(
new VirtualQueue<>(list1),
new VirtualQueue<>(list2),
new VirtualQueue<>(list3));
int n=10;
var value = IntStream.range(0,n)
.mapToObj(i -> listList.stream()
.filter(VirtualQueue::hasMore)
.min(Comparator.comparing(l -> l.peek()))
.get().pop())
.skip(n-1).findFirst().get();
//value is now the nth item in a hypothetical merged list.
Assuming that you have k sorted Lists, and you need to obtain the n from the aggregated List (but the merged list itself don't needed), then this problem can be solved in O(n * log k) time, and by using O(k) additional space.
Note:
If the code below looks too much involved, here's the rationale behind that. This solution is more performant than straightforward comparison of elements from each list which can be observed in this and this answers, which time complexity O(n * k) (opposed to O(n * log k)). A moderate additional complexity is a cost of the performance gain, and note that it's still maintainable.
In case you would need to materialize the merged sorted list (solution below is not doing this), you can simply combine the lists together and make use of the built-in Timsort algorithm implementation via List.sort(). Timsort is very good at spotting the sorted runs, therefore sorting a list that consists of sorted chunks would have a linear time complexity.
To address the problem in O(n * log k) time, we can maintain a PriorityQueue which would always have a size of k or less (therefore enqueue/dequeue operation would have a cost of O(log k)). At the beginning, the Queue should be initialized by adding the very first element from each List.
Then we need to perform n iteration (to find the target element). At each iteration step the Head element of the Queue should be removed, and the next element originated from the same list should be added to the Queue (i.e. if let's say the 7th element from the 3rd List appear to be the Head of the Queue, then after removing it, we need to enqueue the 8th element from the 3rd List).
In order to be able to track from which List each element is coming from and what was its index in the List, we can define a custom type:
public class ElementWrapper<V extends Comparable<V>> implements Comparable<ElementWrapper<V>> {
private V value;
private int listIndex;
private int elementIndex;
// all-args constructor, getters
#Override
public int compareTo(ElementWrapper<V> o) {
return value.compareTo(o.getValue());
}
}
And here's how this algorithm for finding the n-th element can be implemented. As I've said, the time complexity is O(n * log k), since we need n iteration step with each step having a cost of O(log k). Additional memory required only to maintain a Queue of k element.
public static <T extends Comparable<T>> T getNElement(List<List<T>> lists, int n) {
Queue<ElementWrapper<T>> queue = initializeWithFirstElements(lists);
T result = null;
int count = 1;
while (!queue.isEmpty()) {
ElementWrapper<T> current = queue.remove();
if (count == n) { // target index was reached
result = current.getValue();
break;
}
count++;
if (hasNext(current, lists)) {
addNext(current, lists, queue);
}
}
return result;
}
public static <T extends Comparable<T>> Queue<ElementWrapper<T>>
initializeWithFirstElements(List<List<T>> lists) {
Queue<ElementWrapper<T>> queue = new PriorityQueue<>();
for (int i = 0; i < lists.size(); i++) {
if (lists.get(i).isEmpty()) continue;
queue.add(new ElementWrapper<>(lists.get(i).get(0), i, 0));
}
return queue;
}
public static <T extends Comparable<T>> boolean
hasNext(ElementWrapper<T> current, List<List<T>> lists) {
return current.getElementIndex() + 1 < lists.get(current.getListIndex()).size();
}
public static <T extends Comparable<T>> void
addNext(ElementWrapper<T> current, List<List<T>> lists,
Queue<ElementWrapper<T>> queue) {
ElementWrapper<T> next = new ElementWrapper<>(
lists.get(current.getListIndex()).get(current.getElementIndex() + 1),
current.getListIndex(),
current.getElementIndex() + 1
);
queue.add(next);
}
Usage example:
public static void main(String[] args) {
List<List<Integer>> input =
List.of(List.of(1, 3), List.of(),
List.of(2, 6, 7), List.of(10), List.of(4, 5, 8, 9)
);
System.out.println(getNElement(input, 1));
System.out.println(getNElement(input, 3));
System.out.println(getNElement(input, 9));
}
Output:
1 // 1st
3 // 3rd
9 // 9th
Note: depending how do you want the n-th element to be indexed the count variable in the getNElement() method should be initialized accordingly, i.e. with 1 if you want to use 1-based indexes, and with 0 if you want n to be 0-based.
I am trying to create a method that removes every Nth element from a List of unknown type (Wildcard), however every way I try doing it, it doesn't remove the specified elements, but I cannot figure out why. I have been struggling with this for two days now, so I am posting here as a last resort. I thank you in advance for any help.
The code I currently have is as follows:
public static void removeEveryNthElement(List<?> list, int n) {
//Set list equal to an ArrayList because List is immutable
list = new ArrayList<>(list);
//If n is negative or zero throw an exception
if(n <= 0) {
throw new IllegalArgumentException("Integer n needs to be a positive number.");
}
//If the list is null, throw an exception
if(list == null) {
throw new NullPointerException("The list must not be null.");
}
//Remove every nth element in the list
for(int i = 0; i < list.size(); i++) {
if(i % n == 0) {
list.remove(i);
}
}
The other way I have attempted is replacing the for loop with the following:
list.removeIf(i -> i % 3 == 0);
However, when I do it like this I receive the error that the % operator is undefined for the argument type.
I have also tried using a for loop to individually add each element from the list into another modifiable list, but no matter what I do, I am having no luck. If you could help me with this it would be greatly appreciated!
The most serious problem with your code is that removing an element at index i changes the index of all following elements and therefore your condition for removing elements (i % n) is wrong after removing the first element.
One way to get around the problem is iterating in reverse order:
for (int i = list.size()-1; i >= 0; i--) {
if (i % n == 0) {
list.remove(i);
}
}
Another way is to increment i not by one, but by n and adjust it for the removed element:
for (int i = 0; i < list.size(); i += n) {
list.remove(i);
i--;
}
and, since i--; followed by i += n; is the same as i += n-1;:
for (int i = 0; i < list.size(); i += n-1) {
list.remove(i);
}
An additional note: the check if (list == null) is useless after the statement list = new ArrayList<>(list);, since new ArrayList<>(list); already throws a NullPointerException if list is null
You need to keep in mind that creating new collection based on other collection is removing references to oryginal collection - values from collection are coppied to new one - any modification will not impact anything that is out of method scope. You'll need to pass the collection that supports deleting an object from itself or return new collection from method. Remember that the type does not define behaviour of object - its depending on the implementation that is compatible with class you cast to. Here is an example of what I said about the backend implementation (both variables are type List but the implementation is different).
Here is code when you want to do this 'in place':
public static void main(String[] args) {
List<Integer> list2 = new ArrayList<>();
list2.add(1);
list2.add(2);
list2.add(3);
list2.add(4);
removeEveryNthElement(list2, 3); // deleted number 3 because it is 3rd element
}
public static void removeEveryNthElement(List<?> list, int n) {
for (int i = 2; i < list.size(); i += 3) {
list.remove(i);
}
}
But I would like to recommend not to do any operation that is not transparent to programmer. It's better to read and understand bigger programms when you know that you pass value to method and 'it does something' then get value back because it got changed. For this example I use generics and streams:
public static void main(String[] args) {
List<Integer> list1 = Arrays.asList(1, 2, 3, 4);
list1 = removeEveryNthElement2(list1, 3); //deleted number 3
System.out.println();
}
public static <T> List<T> removeEveryNthElement2(List<T> list, int n) {
final Predicate<T> p = new Predicate<T>() {
int i = 0;
#Override
public boolean test(final T t) {
return ++i % n != 0;
}
};
return list.stream().filter(p).collect(Collectors.toList());
}
Brandon, let me first suggest that your method is side-effecting the list built in the calling method. This is allowed, but can lead to hard-to-understand bugs in more complicated code. Instead, try making a new list in your method, and assigned the returned value:
public class Remove {
public static void main(String[] args) {
List<String> list = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h");
list = removeElements(list, 3);
System.out.println(list);
}
public static <T> List<T> removeElements(List<T> list, int n) {
List<T> newList = new ArrayList<T>();
for (int i = 0; i < list.size(); i++) {
if (i % n != 0) {
newList.add(list.get(i));
}
}
return newList;
}
}
As a result, it makes the method simpler, because we're no longer iterating over the list being modified.
Have a look at Side effect--what's this?
to read more about side-effecting.
help here will be greatly appreciated. I'm pretty stuck. What I have to do is I have to use the selection sort algorithm to sort an arraylist, but there are multiple indexes in each object in the arraylist. This has to be done in java.
For example:
public class a {
private int number;
private String letter;
public a(int n, String l)
{
number = n;
letter = l;
}
}
public class SortingArrays {
private ArrayList<a> myarray;
private Comparator<a> sortByNumber;
private Comparator<a> sortByLetter;
public FootballPlayerData() {
myarray = new ArrayList<a>();
getmyarray().add(new a(2, "A"));
getmyarray().add(new a(7, "J"));
//COMPARATORs//
sortByNumber = new Comparator<a>() {
#Override
public int compare(a o1, a o2)
{
if (o1.number < (o2.number)) {
return -1;
}
if (o1.number == (o2.number)) {
return 0;
}
return 1;
}
};
sortByLetter = new Comparator<a>() {
#Override
public int compare(a o1, a o2)
{
return o1.letter.compareTo(o2.letter);
}
};
public void selectionSortbyNumber
{
???
}
public void selectionSortbyLetter
{
???
}
}
So how do I create a selection sort in java (has to be selection sort) that sorts the arraylist by different elements within the objects? I already have the comparator part down, but I don't know how to incorporate that with selection sort.
A Comparator implementation is usually used to compare two elements with one another, returning -1 (or any negative number) if the first element is less than the second, 0 if they are equal, and 1 (or any positive number) if the first element is greater than the second. This can be used to compare two elements to see if one is greater, less than, or equal to the other.
In the context of selection sort, you can use a supplied comparator to determine which value in the unsorted portion of the list is the minimum. The general algorithm for selection sort is as follows:
for i from 0 to array.length:
current_minimum_index = i
for j from i + 1 to array.length:
if array at j is less than array at current_minimum_index:
current_minimum_index = j
swap array at current_minimum_index with array at i
The if array at j is less than array at current_minimum_index can be implemented using Comparator. For example, given a supplied ArrayList called array, the call to the Comparator object named comparator would be:
if (comparator.compare(array.get(j), array.get(current_minimum_index))) < 0)
I do not want to provide you with the complete answer, as that would not help you learn selection sorting, but the method signature for your sorting would resemble the following:
public <T> void selectionSort(ArrayList<T> array, Comparator<T> comparator) {
// for i from 0 to array.size():
// currentMinIndex = i
// for j from i + 1 to array.size():
if (comparator.compare(array.get(j), array.get(currentMinIndex))) < 0) {
// currentMinIndex = j
}
// swap array at currentMinIndex with array at i
}
Your call to this method would then look like one of the following:
selectionSort(myarray, sortByNumber);
selectionSort(myarray, sortByLetter);
Source from https://en.wikipedia.org/wiki/Selection_sort:
/* a[0] to a[n-1] is the array to sort */
int i,j;
int n;
/* advance the position through the entire array */
/* (could do j < n-1 because single element is also min element) */
int iMin;
for (j = 0; j < n-1; j++) {
/* find the min element in the unsorted a[j .. n-1] */
/* assume the min is the first element */
iMin = j;
/* test against elements after j to find the smallest */
for (i = j+1; i < n; i++) {
/* if this element is less, then it is the new minimum */
if (a[i] < a[iMin]) {
/* found new minimum; remember its index */
iMin = i;
}
}
}
if (iMin != j) {
swap(a[j], a[iMin]);
}
The method swap() just switch the values in the array.
Your job will be to swap the array with list. :P But that's not so hard because you can access the list value by index get(int index) method.
In my problem I have few arrays with numbers 1 - 3,
[1,2,3], [1,2,3]
I combined the arrays into one full array,
[1,2,3, 1,2,3]
I need to randomize the array each run, so that no element repeats.
For example, this would work
[1, 2, 1, 3, 2, 3]
but this would not.
[1,2,2,3,1,3]
I chose 1,2,3 to simplify it, but my arrays would consist of the numbers 1 - 6. The idea remains the same though. Is there an algorithm or easy method to accomplish this?
This is a heuristic solution for random shuffling not allowing consecutive duplicates. It applies to lists, but it's easy to transfer it to arrays as it does only swapping and no shift operations are required. It seems to work in the majority of cases for lists consisting of millions of elements and various density factors, but always keep in mind that heuristic algorithms may never find a solution. It uses logic from genetic algorithms, with the exception that this version utilizes one individual and selective mutation only (it's easy to convert it to a real genetic algorithm though), but it's simple and works as follows:
If a duplicate is found, try swapping it with a random element after it; if not possible, try swapping it with an element prior to it (or vice versa). The key point here is the random position for exchanging elements, so as to keep a better uniform distribution on random output.
This question has been asked in alternative forms, but I couldn't find an acceptable solution yet. Unfortunately, as most of the proposed answers (except for the "greedy" extensive re-shuffling till we get a match or computing every combination), this solution does not provide a perfect uniform distribution, but seems to minimize some patterns, :( still not possible to remove every pattern, as you see below. Try it and post any comments for potential improvements.
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
//Heuristic Non-Consecutive Duplicate (NCD) Shuffler
public class NCDShuffler {
private static Random random = new Random();
//private static int swaps = 0;
public static <T> void shuffle (List<T> list) {
if (list == null || list.size() <= 1) return;
int MAX_RETRIES = 10; //it's heuristic
boolean found;
int retries = 1;
do {
Collections.shuffle(list);
found = true;
for (int i = 0; i < list.size() - 1; i++) {
T cur = list.get(i);
T next = list.get(i + 1);
if (cur.equals(next)) {
//choose between front and back with some probability based on the size of sublists
int r = random.nextInt(list.size());
if ( i < r) {
if (!swapFront(i + 1, next, list, true)) {
found = false;
break;
}
} else {
if (!swapBack(i + 1, next, list, true)) {
found = false;
break;
}
}
}
}
retries++;
} while (retries <= MAX_RETRIES && !found);
}
//try to swap it with an element in a random position after it
private static <T> boolean swapFront(int index, T t, List<T> list, boolean first) {
if (index == list.size() - 1) return first ? swapBack(index, t, list, false) : false;
int n = list.size() - index - 1;
int r = random.nextInt(n) + index + 1;
int counter = 0;
while (counter < n) {
T t2 = list.get(r);
if (!t.equals(t2)) {
Collections.swap(list, index, r);
//swaps++;
return true;
}
r++;
if (r == list.size()) r = index + 1;
counter++;
}
//can't move it front, try back
return first ? swapBack(index, t, list, false) : false;
}
//try to swap it with an element in a random "previous" position
private static <T> boolean swapBack(int index, T t, List<T> list, boolean first) {
if (index <= 1) return first ? swapFront(index, t, list, false) : false;
int n = index - 1;
int r = random.nextInt(n);
int counter = 0;
while (counter < n) {
T t2 = list.get(r);
if (!t.equals(t2) && !hasEqualNeighbours(r, t, list)) {
Collections.swap(list, index, r);
//swaps++;
return true;
}
r++;
if (r == index) r = 0;
counter++;
}
return first ? swapFront(index, t, list, false) : false;
}
//check if an element t can fit in position i
public static <T> boolean hasEqualNeighbours(int i, T t, List<T> list) {
if (list.size() == 1)
return false;
else if (i == 0) {
if (t.equals(list.get(i + 1)))
return true;
return false;
} else {
if (t.equals(list.get(i - 1)) || (t.equals(list.get(i + 1))))
return true;
return false;
}
}
//check if shuffled with no consecutive duplicates
public static <T> boolean isShuffledOK(List<T> list) {
for (int i = 1; i < list.size(); i++) {
if (list.get(i).equals(list.get(i - 1)))
return false;
}
return true;
}
//count consecutive duplicates, the smaller the better; We need ZERO
public static <T> int getFitness(List<T> list) {
int sum = 0;
for (int i = 1; i < list.size(); i++) {
if (list.get(i).equals(list.get(i - 1)))
sum++;
}
return sum;
}
//let's test it
public static void main (String args[]) {
HashMap<Integer, Integer> freq = new HashMap<Integer, Integer>();
//initialise a list
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(1);
list.add(2);
list.add(3);
/*for (int i = 0; i<100000; i++) {
list.add(random.nextInt(10));
}*/
//Try to put each output in the frequency Map
//then check if it's a uniform distribution
Integer hash;
for (int i = 0; i < 10000; i++) {
//shuffle it
shuffle(list);
hash = hash(list);
if (freq.containsKey(hash)) {
freq.put(hash, freq.get(hash) + 1);
} else {
freq.put(hash, 1);
}
}
System.out.println("Unique Outputs: " + freq.size());
System.out.println("EntrySet: " + freq.entrySet());
//System.out.println("Swaps: " + swaps);
//for the last shuffle
System.out.println("Shuffled OK: " + isShuffledOK(list));
System.out.println("Consecutive Duplicates: " + getFitness(list));
}
//test hash
public static int hash (List<Integer> list) {
int h = 0;
for (int i = 0; (i < list.size() && i < 9); i++) {
h += list.get(i) * (int)Math.pow(10, i); //it's reversed, but OK
}
return h;
}
}
This is a sample output; it's easy to understand the issue with the non-uniform distribution.
Unique Outputs: 6
EntrySet: [1312=1867, 3121=1753, 2131=1877, 1321=1365, 1213=1793, 1231=1345]
Shuffled OK: true
Consecutive Duplicates: 0
You could use Collections.shuffle to randomize the list. Do it in a while loop, until the list passes your constraint.
If the arrays are relatively small, it would not be too hard for you just to combine the two arrays, randomize it then check the numbers, and if there are too same numbers just shift one over or just randomize it again.
There's no pre-written algorithm that I know of (which doesn't mean one doesn't exist), but the problem is easy to understand and the implementation is straightforward.
I will offer two suggestions dependent on if you want to build a valid array or if you want to build an array and then check its validity.
1 - Create some collection (Array, ArrayList, etc) that contains all of the possible values that will be included in your final array. Grab one of those values and add it to the array. Store a copy of that value in a variable. Grab another value from the possible values, check that it's not equal to your previous value, and add it to the array if it's valid.
2 - Create an array that contains the number of values you want. Check that item n != item n+1 for all items except the last one. If you fail one of those checks, either generate a new random value for that location or add or subtract some constant from the value at that location. Once you have checked all of the values in this array, you know you have a valid array. Assuming the first and last values can be the same.
The most optimal solution, I can think of, is to count the number of occurrences of each value, logically creating a "pool" for each distinct value.
You then randomly choose a value from any of the pools that are not the value of the previous selection. The random selection is weighted by pool sizes.
If a pool is more than half the size of all remaining values, then you must choose from that pool, in order to prevent repetition at the end.
This way you can produce result fast without any form of retry or backtracking.
Example (using letters as values to clarify difference from counts):
Input: A, B, C, A, B, C
Action Selected Pools(Count)
A(2) B(2) C(2)
Random from all 3 pools A A(1) B(2) C(2)
Random from B+C pools C A(1) B(2) C(1)
Random from A+B pools (1:2 ratio) A A(0) B(2) C(1)
Must choose B (>half) B A(0) B(1) C(1)
Random from A+C, so C C A(0) B(1) C(0)
Must choose B (>half) B A(0) B(0) C(0)
Result: A, C, A, B, C, B
Consider the following Accumulator class with a missing method
'prodA(int m)'
which is supposed to return the product of all elements of the array A
if such product is less than or equal to m and return m otherwise.
For example if A is the array {2,4,3} then
prodA(2) will return 2
prodA(0) will return 0
prodA(50) will return 24
(Hint: the length of an array A is given by A.length)
Insert the code for the body of the method prodA where
marked.
public class Accumulator {
private int[] A;
public Accumulator(int[] X) {
A= new int[X.length];
for (int i=0; i<X.length; i++)
A[i] = X[i];
}
public int prodA(int m) {
// insert your code here
}
}
You simply multiply the elements of the array A, then check if the sum is smaller than m, if so, you return it, otherwise you return m.
I won't show you a full solution, but computing the multiplication of the elements is extremely easy, you should have an int res = 1; and then multiply it by each element from the array and reassign the result to res (using a loop).
int prod=1;
for(int i:A){
prod=prod*i;
}
if(prod<m)
return prod;
else
return m;
int product=1;
for(int num:A) {
product=product*num;
}
return (product<=m)?product:m;
There are not many things to consider here, but three come to my mind:
How to treat the empty array? I assume that the result should be 1 in this case, as it lends itself by being the neutral element of multiplication
How large is the array? Might it be worth to implement an "early return"? That is, when the array contains 1000000 elements, and you notice that the result of multiplying the first 2 elements already is greater than the limit, you could already return this limit, and not waste time by performing the remaining 999998 multiplications (assuming that the array does not contains zeros!)
How to structure the methods? I think that separating the computation of the product and the computation of the actual result, like return Math.min(limit, product(A)) with an appropriate product method that only has the single responsibility of computing a product of the elements of an array. However, this makes the "early return" impossible.
The "early return" could do something like this:
public int prodA(int m)
{
int product = 1;
for (int i = 0; i < A.length; i++)
{
product *= A[i];
if (product >= m)
{
return m;
}
}
return product;
}
while from a standpoint of reusability, something like this might be nicer:
public int prodA(int m)
{
return Math.min(m, product(A));
}
private static int product(int array[] )
{
int product = 1;
for (int i = 1; i < array.length; i++)
{
product *= array[i];
}
return product;
}
public int prodA(int m) {
int p=1;
for(int i=0;i<A.lenght.i++){
p=p*A[i];
}
if(p<=m)
return p;
else
return m;
}