Following this question : Random distribution of items in list up to a maximum count
I have a List of items containing x items.
I want to distribute these items randomly in other Lists with the conditions :
- Each List has a maximum size of y item (with y = 4)
- Each Item must be used exactly z times (with z = 5)
- Each Item must only appear once in a particular List
If x isn't divisible by both y and z, it's okay to have Lists containing less than y items.
I'm looking for a Java (from 1.6 to 1.8) implementation of such a method.
So far, thanks to Jamie Cockburn, I have a method that can distribute items randomly in other Lists by using them 0 to z
times. I need to use them exactly z
times. His method also allow items be used more than once in a single List.
EDIT
Now I manage to use items exactly z
times in my Lists. But I'm stuck with what to do if the List already contains the same Item :
Here's my function :
public static List<List<Item>> distribute(List<Item> list, int y, int z) {
int x = list.size();
int nLists = (int) Math.ceil((double)(x*z)/y);
// Create result lists
List<List<Item>> result = new ArrayList<>();
for (int j = 0; j < nLists; j++)
result.add(new ArrayList<Item>());
List<List<Item>> outputLists = new ArrayList<>(result);
// Create item count store
Map<Item, Integer> itemCounts = new HashMap<>();
for (Item item : list)
itemCounts.put(item, 0);
// Populate results
Random random = new Random();
for (int i = 0; i < (x*z); i++) {
// Add a random item (from the remaining eligible items)
// to a random list (from the remaining eligible lists)
Item item = list.get(random.nextInt(list.size()));
List<Item> outputList = outputLists.get(random.nextInt(outputLists.size()));
if (outputList.contains(item)) {
// What do I do here ?
} else {
outputList.add(item);
// Manage eligible output lists
if (outputList.size() >= y)
outputLists.remove(outputList);
// Manage eligible items
int itemCount = itemCounts.get(item).intValue() + 1;
if (itemCount >= z)
list.remove(item);
else
itemCounts.put(item, itemCount);
}
}
return result;
}
I deleted my other answer because it was simply wrong! Then it occurred to me that there is a much simpler method:
Basically:
items
repeatedz
timesy
This has the following benefits over the accepted solution:
EDIT:
The general idea is, to create a copy of the input list, and create tempLists out of it, while removing the picked items from the copylist. If the copyList is emptied, it is refilled. This forces all items to be picked once before another is picked twice. If list.size() is devidable by y, the result is qually distributed, if its not, im not sure about.
I changed the Item to Integer to be tested and to find the mistake. Now it operates correctly (I hope, correct for your needs)
reineke