Hello I am relative new in programming and need guidance.
We are on a plantage. I have a number of Fields that contain different amounts of trees. On each field a set of tasks have to be done. The tasks are the same but the time varies since the fields are different sizes. I want to generate a list of tasks that matches the assigned working time for the day best.
I believe this is a Job Shop scheduling problem (NP-hard) but as far as i know it can be solved with brute-force search since the data set is small. How do I generate all combinations within the assigned time and return the best fit? I tried to look at some pseudo code but frankly im quite lost and my attempt is rather poor:
//Brute-force search
// 1. first(P): generate a first candidate solution for P.
// 2. next(P,c): generate the next candidate for P after the current one c.
// 3. valid(P,c): check whether candidate c is a solution for P-
// 4. output(P,c): use the solution c of P as appropriate to the application.
public static ArrayList<Task> generatedList2(int totalTime) {
ArrayList<Task> bestFit = new ArrayList<>();
ArrayList<Task> tmpFit = new ArrayList<>();
int tmpTime = 0;
int bestFitTime = -1;
Task testTask = new Task("TestTask", 0);
bestFit.add(testTask); //1
for(Field f : fields) { //2
for(Task t : f.getUndoneTasks()) {
if(f.getTaskTime(t) < totalTime) {
tmpFit.add(t);
tmpTime += f.getTaskTime(t);
totalTime -= f.getTaskTime(t);
}
}
if(tmpTime < bestFitTime) { //3
bestFit = new ArrayList<Task>(tmpFit);
bestFitTime = tmpTime;
tmpFit.clear();
}
else {
tmpFit.clear();
}
}
return bestFit; //4
}
Updated solution:
public static ArrayList<Task> RecursivelyGetAnswer(ArrayList<Task> listSoFar,
ArrayList<Task> masterList, ArrayList<Task> bestList, int limit, int index) {
for (int i = index; i < masterList.size(); i++) {
Task task = masterList.get(i);
double listSoFarTotal = getTotal(listSoFar) + task.getTaskLength();
if (listSoFarTotal <= limit) {
int bestListTotal = getTotal(bestList);
listSoFar.add(task);
if (listSoFarTotal > bestListTotal) {
bestList = new ArrayList<Task>(listSoFar);
}
else if(100 - ((float) (limit - bestListTotal)/bestListTotal * 100) > 95) {
break;
}
bestList = RecursivelyGetAnswer(listSoFar, masterList, bestList, limit, i+1);
listSoFar.remove(task);
}
}
return bestList;
}
I came up with a recursive solution. For the purposes of my solution, I assumed that you just had a list of tasks, instead of tasks inside fields.
import java.util.ArrayList;
class Task
{
public int taskLength;
public Task(int taskLength)
{
this.taskLength = taskLength;
}
#Override
public String toString()
{
return "T" + taskLength;
}
}
public class Answers
{
public static void main(String args[])
{
ArrayList masterList = new ArrayList();
//Add some sample data
masterList.add(new Task(555));
masterList.add(new Task(1054));
masterList.add(new Task(888));
masterList.add(new Task(5923));
masterList.add(new Task(2342));
masterList.add(new Task(6243));
masterList.add(new Task(9227));
masterList.add(new Task(4111));
masterList.add(new Task(4322));
masterList.add(new Task(782));
final int limit = 9999;
ArrayList<Task> bestList = RecursivelyGetAnswer(new ArrayList<>(), masterList, new ArrayList<>(), limit, 0);
System.out.println(bestList.toString());
System.out.println(getTotal(bestList));
}
public static ArrayList<Task> RecursivelyGetAnswer(ArrayList<Task> listSoFar, ArrayList<Task> masterList, ArrayList<Task> bestList, int limit, int index)
{
for (int i = index; i < masterList.size(); i++)
{
Task task = masterList.get(i);
if (getTotal(listSoFar) + task.taskLength <= limit)
{
listSoFar.add(task);
if (getTotal(listSoFar) > getTotal(bestList))
{
bestList = new ArrayList(listSoFar);
}
bestList = RecursivelyGetAnswer(listSoFar, masterList, bestList, limit, i+1);
listSoFar.remove(task);
}
}
return bestList;
}
// Given a list of tasks, get the sum of the lengths of the tasks.
public static int getTotal(ArrayList<Task> myList)
{
int sum = 0;
for (Task t:myList)
sum += t.taskLength;
return sum;
}
}
Related
Hello everyone I was given the assignment in which I have
In main, you create a queue with generated Strings
word genereting should be done in main
You pass it to executeTasks, they are split into the appropriate lists
I have a problem with referencing things in code
it is still confusing for me☹️
it was much easier on the numbers
Write a program that in the ArrayDeque queue will put 50 objects storing strings (strings), consisting of the letter 'a' repeated a random number of times (repeat range: 1-50).
Filling the object with the repeats of the letter 'a' can be done with a for loop.
Part 2
Extend the program from the first part in such a way that you pass the created queue to the method of your class, which will separate the objects from the queue into two ArrayList collections.
One of them will hold objects with an even number of 'a' characters, the other one with an odd number.
in general, I have done the task in a slightly different way, but I need to correct it
import java.util.*;
import java.lang.*;
class TaskManager {
List<String> executedTasks;
List<String> even;
List<String> odd;
// constructor
public TaskManager() {
executedTasks = new ArrayList<>();
even = new ArrayList<>();
odd = new ArrayList<>();
}
//method serving the list of tasks
public void executeTasks(Deque<String> theQueue) {
while (theQueue.size() > 0) {
String theTask = theQueue.poll();
System.out.println("Processing the task: " + theTask);
char c = 'a';
for (int n = 0; n < 50; n++) {
String result = "";
int count = (char) (Math.random() * 50 + 1);
for (int i = 0; i < count; i++) {
result += c;
}
System.out.println(result);
if (result.length() % 2 == 0) {
even.add(result);
} else {
odd.add(result);
}
executedTasks.add(theTask);
System.out.println("\nExecuted total " + executedTasks.size() + " tasks\n");
}
}
}
}
/* Name of the class has to be "Main" only if the class is public. */
public class QueuesAndLoops {
public static void main(String[] args) throws java.lang.Exception {
char c = 'a';
Deque<String> taskQueue1 = new ArrayDeque<>();
for (int n = 0; n < 1; n++) {
taskQueue1.offer("The first task number " + (n + 1));
}
TaskManager taskExecutor = new TaskManager();
taskExecutor.executeTasks(taskQueue1);
System.out.println("Parzyste:");
System.out.println(taskExecutor.even);
System.out.println("Nieparzyste:");
System.out.println(taskExecutor.odd);
}
}
and this code works but I have a problem to change it to the required version
no one replied but it was about reworking it in a similar way
import java.util.*;
import java.lang.*;
class TaskManager {
List<String> even;
List<String> odd;
// constructor
public TaskManager() {
even = new ArrayList<>();
odd = new ArrayList<>();
}
//method serving the list of tasks
public void executeTasks(Deque<String> theQueue) {
String task;
while ((task = theQueue.poll()) != null) {
System.out.println(task);
boolean isAdded = task.length() % 2 == 0 ? even.add(task) : odd.add(task);
}
}
}
public class QueuesAndLoops {
public static void main(String[] args) throws java.lang.Exception {
final int NUM_TASKS = 50;
String chr = "a";
Deque<String> taskQueue1 = new ArrayDeque<>();
for (int i = 0; i < NUM_TASKS; i++) {
taskQueue1.offer(chr.repeat((int) (Math.random() * 50 + 1)));
}
TaskManager taskExecutor = new TaskManager();
taskExecutor.executeTasks(taskQueue1);
System.out.println("Even:");
System.out.println(taskExecutor.even);
System.out.println("Odd:");
System.out.println(taskExecutor.odd);
}
}
Basically I have this code that is using multiple threads to execute a merge sort algorithm I hope to scale this up to N given threads but currently I'm just trying to get four to work. Basically I create four different threads and pass each of them a subarray of the whole. After they've executed I have 4 different sorted sub-arrays that I then need to merge. Because I'm not really sure how to close threads and clear those resources entirely I am trying to reuse two of those threads to absorb a given array into their internal arrays and then re-run the thread with a boolean which tells the thread to merge the two halves rather than sort everything again. This seems to work the first time when I try with merger 0, and merger 1, but then when I try to do the same thing with 2 and three I get a concurrent modification exception. Now I'm not really sure what I'm doing wrong and if anyone has suggestions on how I could improve this code or reduce the number of array creations and copies that would be greatly appreciated.
import java.util.ArrayList;
import java.util.List;
public class RecursiveSimples {
public static void main(String[] args) throws InterruptedException {
List<Comparable> nums = new ArrayList<Comparable>();
nums.add(7); nums.add(4);
nums.add(8); nums.add(6);
nums.add(1); nums.add(3);
nums.add(4); nums.add(7);
nums.add(2); nums.add(1);
nums.add(5); nums.add(9);
nums.add(8); nums.add(3);
nums.add(2); nums.add(2);
System.out.println(Runtime.getRuntime().availableProcessors());
int r = nums.size() % 4;
int num = nums.size() / 4;
List<Merger> mergers = new ArrayList<Merger>();
mergers.add(new Merger(nums.subList(0, num)));
mergers.add(new Merger(nums.subList(num, num*2)));
mergers.add(new Merger(nums.subList(num*2, num*3)));
mergers.add(new Merger(nums.subList(num*3, (num*4) +r)));
mergers.get(0).start(); mergers.get(1).start();
mergers.get(2).start(); mergers.get(3).start();
mergers.get(0).join(); mergers.get(1).join();
mergers.get(2).join(); mergers.get(3).join();
System.out.println(mergers.get(0).getNums());
System.out.println(mergers.get(1).getNums());
System.out.println(mergers.get(2).getNums());
System.out.println(mergers.get(3).getNums());
mergers.get(0).absorbList(mergers.get(1).getNums());
mergers.get(0).setMerger(true);
mergers.get(0).run();
System.out.println(mergers.get(0).getNums());
mergers.get(2).absorbList(mergers.get(3).getNums());
mergers.get(2).setMerger(true);
mergers.get(2).run();
System.out.println(mergers.get(1).getNums());
System.out.println(mergers.get(3).getNums());
int maxThreads = nums.size() / 2;
}
}
class Merger extends Thread {
private List<Comparable> nums;
private boolean merge = false;
public List<Comparable> getNums() {
return nums;
}
public void setMerger(boolean bool) {
merge = bool;
}
public void absorbList(List<Comparable> list) {
nums.addAll(list);
}
Merger(List<Comparable> arr) {
nums = arr;
}
public void run() {
if(merge == false) {
mergeSort(nums, 0, nums.size() -1);
}else {
merge(nums, 0, (nums.size() -1)/2, nums.size() -1);
}
}
public static void swap(List<Comparable> nums, int index1, int index2)
{
Comparable temp;
temp = nums.get(index1);
nums.set(index1, nums.get(index2));
nums.set(index2, temp);
}
private static void mergeSort(List<Comparable> nums, int first, int last) {
if (first < last)
{
int m = (first+last)/2;
mergeSort(nums, first, m);
mergeSort(nums, m+1, last);
merge(nums, first, m, last);
}
}
private static void merge(List<Comparable> nums, int first, int mid, int last){
List<Comparable> newList = new ArrayList<Comparable>();
int loopCountA = 0;
int loopCountB = 0;
while(true) {
if(loopCountB == (last - mid)) {
while(first + loopCountA <= mid) {
newList.add(nums.get(first + loopCountA)); loopCountA++;
}
break;
}else if(first + loopCountA > mid) {
while(loopCountB < (last - mid)) {
newList.add(nums.get(mid + (loopCountB + 1))); loopCountB++;
}
break;
}else {
if(nums.get(mid + (loopCountB + 1)).compareTo(nums.get(first + loopCountA)) < 0) {
newList.add(nums.get(mid + (loopCountB + 1)));
loopCountB++;
}else {
newList.add(nums.get(first + loopCountA));
loopCountA++;
}
}
}
for(int i = 0; (i - 1) < (last - first); i++)
nums.set(first + i, newList.get(i));
}
}
I would say the problem here (causing the exception) is the way you create sublists - you are using subList(...) method, but it doesn't create another list, just a view for existing one. When you process these different views of one list in different threads you are causing the exception (as every thread changes the same list).
Possible solution would be to change the method to create a sub list or modify constructor to keep a copy, e.g.:
Merger(List<Comparable> arr) {
nums = new ArrayList<>(arr);
}
Write a method to return the Toy that occurs in the list most frequent and another method to sort the toys by count.
This is my code
import java.util.ArrayList;
public class ToyStore {
private ArrayList<Toy> toyList;
public ToyStore() {
}
public void loadToys(String toys) {
toyList = new ArrayList<Toy>();
for (String item : toys.split(" ")) {
Toy t = getThatToy(item);
if (t == null) {
toyList.add(new Toy(item));
} else {
t.setCount(t.getCount() + 1);
}
}
}
public Toy getThatToy(String nm) {
for (Toy item : toyList) {
if (item.getName().equals(nm)) {
return item;
}
}
return null;
}
public String getMostFrequentToy() {
int position = 0;
int maximum = Integer.MIN_VALUE;
for (int i = toyList.size() - 1; i >= 0; i--) {
if (toyList.get(i).getCount() > maximum)
maximum = toyList.get(i).getCount();
position = i;
}
return toyList.get(position).getName();
}
public void sortToysByCount() {
ArrayList<Toy> t = new ArrayList<Toy>();
int count = 0;
int size = toyList.size();
for (int i = size; i > 0; i--) {
t.add(new Toy(getMostFrequentToy()));
t.get(count).setCount(getThatToy(getMostFrequentToy()).getCount());
toyList.remove(getThatToy(getMostFrequentToy()));
count++;
}
toyList = t;
}
public String toString() {
return toyList + "" + "\n" + "max == " + getMostFrequentToy();
}
}
Here is the method I care about
public void sortToysByCount() {
ArrayList<Toy> t = new ArrayList<Toy>();
int count = 0;
int size = toyList.size();
for (int i = size; i > 0; i--) {
t.add(new Toy(getMostFrequentToy()));
t.get(count).setCount(getThatToy(getMostFrequentToy()).getCount());
toyList.remove(getThatToy(getMostFrequentToy()));
count++;
}
toyList = t;
}
Here is my output
[sorry 4, bat 1, train 2, teddy 2, ball 2]
Here is what I want
[sorry 4, train 2, teddy 2, ball 2, bat 1];
What is wrong in my code? How do I do it?
The problem is in your getMostFrequentToy() method:
Replace
if (toyList.get(i).getCount() > maximum)
maximum = toyList.get(i).getCount();
position = i;
with
if (toyList.get(i).getCount() > maximum) {
maximum = toyList.get(i).getCount();
position = i;
}
because you want to get the position that corresponds to that maximum.
You have some in-efficiencies in your code. Every single time you call getMostFrequentToy(), you are iterating over the whole list, which may be fine as you are constantly removing objects, but you really don't need to make new Toy objects for those that already exist in the list.
So, this is "better", but still not sure you need to getThatToy when you should already know which one is the most frequent.
String frequent;
for (int i = size; i > 0; i--) {
frequent = getMostFrequentToy();
t.add(new Toy(frequent));
t.get(count).setCount(getThatToy(frequent).getCount());
toyList.remove(getThatToy(frequent));
count++;
}
Anyways, I think the instructions asked you to return the Toy object, not its name.
It's quite simple, just keep track of the max count.
public Toy getMostFrequentToy() {
Toy mostFrequent = null;
int maximum = Integer.MIN_VALUE;
for (Toy t : toyList) {
if (t.getCount() > maximum)
mostFrequent = t;
}
return t;
}
Now, the above code can become
public void sortToysByCount() {
ArrayList<Toy> t = new ArrayList<Toy>();
// int count = 0;
int size = toyList.size();
Toy frequent;
for (int i = size; i > 0; i--) {
frequent = getMostFrequentToy();
t.add(frequent);
// t.get(count).setCount(frequent.getCount()); // Not sure about this
toyList.remove(frequent);
// count++;
}
toyList.clear();
toyList.addAll(t);
}
Realistically, though, when you want to sort, you really should see how to create a Comparator for your Toy objects.
I have a simple file that contains two integer values per line (a source integer and a target integer). Each line represents a relation between two values. The file is not sorted and the actual file contains about 4 million lines. After sorting it may look like this:
sourceId;targetId
1;5
2;3
4;7
7;4
8;7
9;5
My goal is to create a new object that will represent all unique related integers in a list with a unique identifier. The expected output of this example should be the following three objects:
0, [1, 5, 9]
1, [2, 3]
2, [4, 7, 8]
So groupId 0 contains a group of relations (1, 5 and 9).
Below is my current way to create a list of these objects. The list of Relation objects contains all the lines in memory. And the list of GroupedRelation should be the end result.
public class GroupedRelationBuilder {
private List<Relation> relations;
private List<GroupedRelation> groupedRelations;
private List<String> ids;
private int frameId;
public void build() {
relations = new ArrayList<>();
relations.add(new Relation(1, 5));
relations.add(new Relation(4, 7));
relations.add(new Relation(8, 7));
relations.add(new Relation(7, 4));
relations.add(new Relation(9, 5));
relations.add(new Relation(2, 3));
// sort
relations.sort(Comparator.comparing(Relation::getSource).thenComparing(Relation::getTarget));
// build the groupedRelations
groupId = 0;
groupedRelations = new ArrayList<>();
for (int i = 0; relations.size() > 0;) {
ids = new ArrayList<>();
int compareSource = relations.get(i).getSource();
int compareTarget = relations.get(i).getTarget();
ids.add(Integer.toString(compareSource));
ids.add(Integer.toString(compareTarget));
relations.remove(i);
for (int j = 0; j < relations.size(); j++) {
int source = relations.get(j).getSource();
int target = relations.get(j).getTarget();
if ((source == compareSource || source == compareTarget) && !ids.contains(Integer.toString(target))) {
ids.add(Integer.toString(target));
relations.remove(j);
continue;
}
if ((target == compareSource || target == compareTarget) && !ids.contains(Integer.toString(source))) {
ids.add(Integer.toString(source));
relations.remove(j);
continue;
}
}
if (relations.size() > 0) {
groupedRelations.add(new GroupedRelation(groupId++, ids));
}
}
}
class GroupedRelation {
private int groupId;
private List<String> relatedIds;
public GroupedRelation(int groupId, List<String> relations) {
this.groupId = groupId;
this.relatedIds = relations;
}
public int getGroupId() {
return groupId;
}
public List<String> getRelatedIds() {
return relatedIds;
}
}
class Relation {
private int source;
private int target;
public Relation(int source, int target) {
this.source = source;
this.target = target;
}
public int getSource() {
return source;
}
public void setSource(int source) {
this.source = source;
}
public int getTarget() {
return target;
}
public void setTarget(int target) {
this.target = target;
}
}
}
When I run this small example program, it takes 15 seconds to create 1000 GroupedRelation objects. To create 1 million GroupedRelation it would take 250 minutes..
I am looking for help in optimizing my code that does get the result I want but simply takes to long.
Is it possible to optimize the iteration in such a way that the expected result is the same but the time it takes to get the expected result is reduced significantly? If this is possible, how would you go about it?
The current implementation is slow due to the ids.contains step.
The time complexity of the ArrayList.contains method is O(n):
to check if it contains an element it checks the elements one by one,
in the worst case scanning the entire list.
You can greatly improve the performance if you change the type of ids from List<String> to Set<String>, and use HashSet<String> instances.
The expected time complexity of Set.contains implementations is O(1),
significantly faster compared to a list.
As much as possible I would attempt to do it in a single pass from source.
import java.io.*;
import java.util.*;
/**
* Created by peter on 10/07/16.
*/
public class GroupedRelationBuilder {
public static List<List<Integer>> load(File file) throws IOException {
Map<Integer, Group> idToGroupMap = new HashMap<>();
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
br.readLine();
for (String line; (line = br.readLine()) != null; ) {
String[] parts = line.split(";");
Integer source = Integer.parseInt(parts[0]);
Integer target = Integer.parseInt(parts[1]);
Group grp0 = idToGroupMap.get(source);
Group grp1 = idToGroupMap.get(target);
if (grp0 == null) {
if (grp1 == null) {
Group grp = new Group();
List<Integer> list = grp.ids;
list.add(source);
list.add(target);
idToGroupMap.put(source, grp);
idToGroupMap.put(target, grp);
} else {
grp1.ids.add(source);
idToGroupMap.put(source, grp1);
}
} else if (grp1 == null) {
grp0.ids.add(target);
idToGroupMap.put(target, grp0);
} else {
grp0.ids.addAll(grp1.ids);
grp1.ids = grp0.ids;
}
}
}
Set<List<Integer>> idsSet = Collections.newSetFromMap(new IdentityHashMap<>());
for (Group group : idToGroupMap.values()) {
idsSet.add(group.ids);
}
return new ArrayList<>(idsSet);
}
static class Group {
List<Integer> ids = new ArrayList<>();
}
public static void main(String[] args) throws IOException {
File file = File.createTempFile("deleteme", "txt");
Set<String> pairs = new HashSet<>();
try (PrintWriter pw = new PrintWriter(file)) {
pw.println("source;target");
Random rand = new Random();
int count = 1000000;
while (pairs.size() < count) {
int a = rand.nextInt(count);
int b = rand.nextInt(count);
if (a < b) {
int t = a;
a = b;
b = t;
}
pairs.add(a + ";" + b);
}
for (String pair : pairs) {
pw.println(pair);
}
}
System.out.println("Processing");
long start = System.currentTimeMillis();
List<List<Integer>> results = GroupedRelationBuilder.load(file);
System.out.println(results.size() + " took " + (System.currentTimeMillis() - start) / 1e3 + " sec");
}
}
For one million pairs this prints
Processing
105612 took 12.719 sec
You implementation is slow due to the Integer.toString() usage.
Changing the type means object and memory allocations. This is now done 4-5 times in the subloop.
Changing it took me from 126ms to 35ms: 4 times faster!
Several other things I see are:
first for loop can be changed into while(!relations.isEmpty())
the second loop could be done by using an iterator for (Iterator<Relation> iterator = relations.iterator(); iterator.hasNext();). When you remove an item, you are now skipping the next.
Place the declaration of ids inside the loop
I have a continuous running thread in my application, which consists of a HashSet to store all the symbols inside the application. As per the design at the time it was written, inside the thread's while true condition it will iterate the HashSet continuously, and update the database for all the symbols contained inside HashSet.
The maximum number of symbols that might be present inside the HashSet will be around 6000. I don't want to update the DB with all the 6000 symbols at once, but divide this HashSet into different subsets of 500 each (12 sets) and execute each subset individually and have a thread sleep after each subset for 15 minutes, so that I can reduce the pressure on the database.
This is my code (sample code snippet)
How can I partition a set into smaller subsets and process (I have seen the examples for partitioning ArrayList, TreeSet, but didn't find any example related to HashSet)
package com.ubsc.rewji.threads;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.PriorityBlockingQueue;
public class TaskerThread extends Thread {
private PriorityBlockingQueue<String> priorityBlocking = new PriorityBlockingQueue<String>();
String symbols[] = new String[] { "One", "Two", "Three", "Four" };
Set<String> allSymbolsSet = Collections
.synchronizedSet(new HashSet<String>(Arrays.asList(symbols)));
public void addsymbols(String commaDelimSymbolsList) {
if (commaDelimSymbolsList != null) {
String[] symAr = commaDelimSymbolsList.split(",");
for (int i = 0; i < symAr.length; i++) {
priorityBlocking.add(symAr[i]);
}
}
}
public void run() {
while (true) {
try {
while (priorityBlocking.peek() != null) {
String symbol = priorityBlocking.poll();
allSymbolsSet.add(symbol);
}
Iterator<String> ite = allSymbolsSet.iterator();
System.out.println("=======================");
while (ite.hasNext()) {
String symbol = ite.next();
if (symbol != null && symbol.trim().length() > 0) {
try {
updateDB(symbol);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void updateDB(String symbol) {
System.out.println("THE SYMBOL BEING UPDATED IS" + " " + symbol);
}
public static void main(String args[]) {
TaskerThread taskThread = new TaskerThread();
taskThread.start();
String commaDelimSymbolsList = "ONVO,HJI,HYU,SD,F,SDF,ASA,TRET,TRE,JHG,RWE,XCX,WQE,KLJK,XCZ";
taskThread.addsymbols(commaDelimSymbolsList);
}
}
With Guava:
for (List<String> partition : Iterables.partition(yourSet, 500)) {
// ... handle partition ...
}
Or Apache Commons:
for (List<String> partition : ListUtils.partition(yourList, 500)) {
// ... handle partition ...
}
Do something like
private static final int PARTITIONS_COUNT = 12;
List<Set<Type>> theSets = new ArrayList<Set<Type>>(PARTITIONS_COUNT);
for (int i = 0; i < PARTITIONS_COUNT; i++) {
theSets.add(new HashSet<Type>());
}
int index = 0;
for (Type object : originalSet) {
theSets.get(index++ % PARTITIONS_COUNT).add(object);
}
Now you have partitioned the originalSet into 12 other HashSets.
We can use the following approach to divide a Set.
We will get the output as
[a, b]
[c, d]
[e]`
private static List<Set<String>> partitionSet(Set<String> set, int partitionSize)
{
List<Set<String>> list = new ArrayList<>();
int setSize = set.size();
Iterator iterator = set.iterator();
while(iterator.hasNext())
{
Set newSet = new HashSet();
for(int j = 0; j < partitionSize && iterator.hasNext(); j++)
{
String s = (String)iterator.next();
newSet.add(s);
}
list.add(newSet);
}
return list;
}
public static void main(String[] args)
{
Set<String> set = new HashSet<>();
set.add("a");
set.add("b");
set.add("c");
set.add("d");
set.add("e");
int size = 2;
List<Set<String>> list = partitionSet(set, 2);
for(int i = 0; i < list.size(); i++)
{
Set<String> s = list.get(i);
System.out.println(s);
}
}
If you are not worried much about space complexity, you can do like this in a clean way :
List<List<T>> partitionList = Lists.partition(new ArrayList<>(inputSet), PARTITION_SIZE);
List<Set<T>> partitionSet = partitionList.stream().map((Function<List<T>, HashSet>) HashSet::new).collect(Collectors.toList());
The Guava solution from #Andrey_chaschev seems the best, but in case it is not possible to use it, I believe the following would help
public static List<Set<String>> partition(Set<String> set, int chunk) {
if(set == null || set.isEmpty() || chunk < 1)
return new ArrayList<>();
List<Set<String>> partitionedList = new ArrayList<>();
double loopsize = Math.ceil((double) set.size() / (double) chunk);
for(int i =0; i < loopsize; i++) {
partitionedList.add(set.stream().skip((long)i * chunk).limit(chunk).collect(Collectors.toSet()));
}
return partitionedList;
}
A very simple way for your actual problem would be to change your code as follows:
Iterator<String> ite = allSymbolsSet.iterator();
System.out.println("=======================");
int i = 500;
while ((--i > 0) && ite.hasNext()) {
A general method would be to use the iterator to take the elements out one by one in a simple loop:
int i = 500;
while ((--i > 0) && ite.hasNext()) {
sublist.add(ite.next());
ite.remove();
}