How to get the records, which count sum should be in limit. In below example there is Records Object contains recordId and count, i wanted to fetch the records data based on the total sum of count should be less than or equal to my limit condition.
public class Records {
private int recordID;
private int count;
public Records(int recordID, int count) {
this.recordID = recordID;
this.count = count;
}
public int getRecordID() {
return recordID;
}
public void setRecordID(int recordID) {
this.recordID = recordID;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
public static void main(String[] args) {
final List<Records> recordList = new ArrayList<>();
recordList.add(new Records(100, 10));
recordList.add(new Records(501, 20));
recordList.add(new Records(302, 5));
recordList.add(new Records(405, 2));
recordList.add(new Records(918, 8));
int limit = 35;
}
Expected Result
recordList should have records objects : [100,10], [500,20], [302,5] records
The problems of solving this with Stream API is that you have to keep some information outside of the context of processing and read/update (depend) on it at the same time. These tasks are not suitable for Stream API.
Use a for-loop instead which is suitable and great for this:
int index = 0; // highest index possible
int sum = 0; // sum as a temporary variable
for (int i=0; i<recordList.size(); i++) { // for each Record
sum += recordList.get(i).getCount(); // ... add the 'count' to the 'sum'
if (sum <= limit) { // ... until the sum is below the limit
index = i; // ... move the pivot
} else break; // ... or else stop processing
}
// here you need to get the list from 0 to index+1
// as long as the 2nd parameter of subList(int, int) is exlcusive
List<Record> filteredRecords = recordList.subList(0, index + 1);
This is the only thing I could come up with but it's not as efficient as a regular loop because it runs for each list entry it has. That also causes it to add other values further down. For example if limit was 46, third entry where count is 5 would be skipped but the next entry with count 2 would be still added. Don't know if this is desired behavior for you
AtomicInteger count = new AtomicInteger();
recordList = recordList.stream().filter(r -> {
if(count.get() + r.count <= limit){
count.addAndGet(r.count);
return true;
}
return false;
}).collect(Collectors.toList());
Adding the following toString to your class for printing you can do it as follows:
public String toString() {
return String.format("[%s, %s]", recordID, count);
}
Allocate a List to store the results
initialize the sum
iterate thru the list, summing the count until the
threshhold is reached.
List<Records> results = new ArrayList<>();
int sum = 0;
for (Records rec : recordList) {
// sum the counts
sum += rec.getCount();
if (sum > limit) {
// stop when limit exceeded
break;
}
results.add(rec);
}
results.forEach(System.out::println);
Prints
[100, 10]
[501, 20]
[302, 5]
with java 8 you can do something like:
public static void main(String[] args) {
int limit = 35;
List<Records> recordList = new ArrayList<>();
recordList.add(new Records(100, 10));
recordList.add(new Records(501, 20));
recordList.add(new Records(302, 5));
recordList.add(new Records(405, 2));
recordList.add(new Records(918, 8));
List<Records> limitedResult = recordList.stream().filter(new Predicate<Records>() {
int sum = 0;
#Override
public boolean test(Records records) {
sum=sum+records.getCount();
return sum <= limit;
}
}).collect(Collectors.toList());
//do what do you want with limitedResult
System.out.println(limitedResult);
}
Edit:
Or you can make function which return Predicate which can be reuse as:
//Reusable predicate
public static Predicate<Records> limitRecordPredicate(int limit){
return new Predicate<Records>() {
int sum = 0;
#Override
public boolean test (Records records){
sum = sum + records.getCount();
return sum <= limit;
}
};
}
and then used it like:
List<Records> limitedResult = recordList.stream().filter(limitRecordPredicate(limit)).collect(Collectors.toList());
//do what do you want with limitedResult
System.out.println(limitedResult);
Output:
[Records[recordID=100, count=10], Records[recordID=501, count=20], Records[recordID=302, count=5]]
Related
So I am supposed to write a program, in which multiple threads add some number of items to a list. I was given two interfaces that I should implement. The number added is a sum of two previous numbers added (like Fibonacci series)
public interface Main
{
List<Integer> sum(int count, int threadCount, int firstElement, int secondElement);
}
and
public interface Sum extends Runnable
{
//how many elements each thread should add
int getHowMany();
List<Integer> getList();
}
So I thought of doing it this way: I create a class DefaultSum, which implements Sum interface, implement methods from it, and in the run() method I would call a method actually adding elements to list.
This is my DefaultSum class
public class DefaultSum implements Sum {
DefaultMain main = new DefaultMain();
DefaultSum() {
}
#Override
public void run() {
int count = getHowMany();
List<Integer> list = getList();
int firstElement = list.get(list.size() - 2).intValue();
int secondElement = list.get(list.size() - 1).intValue();
int j = 2;
while (j < count) {
int adder = firstElement + secondElement;
list.add(adder);
System.out.println(list);
firstElement = secondElement;
secondElement = adder;
if (j == count) {
notifyAll();
}
j++;
}
System.out.println(list);
}
#Override
public int getHowMany() {
try {
Field[] fields = DefaultMain.class.getFields();
for (int i = 0; i < fields.length; i++) {
Object val = fields[i].get(main);
if (fields[i].getName().equalsIgnoreCase("count")) {
int number = (Integer) val;
return number;
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return -1;
}
#Override
public List<Integer> getList() {
try {
Field[] fields = DefaultMain.class.getFields();
for (int i = 0; i < fields.length; i++) {
Object val = fields[i].get(main);
if (fields[i].getName().equalsIgnoreCase("list")) {
return (List<Integer>) val;
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}
And my main class, DefaultMain, where the number of items added is given and user can decide how many threads he wants to work on this list.
public class DefaultMain implements Main {
static int firstElement = 0;
static int secondElement = 1;
static int count = 10;
public static List<Integer> lista = new ArrayList<Integer>();
public static List<Integer> list = Collections.synchronizedList(lista);
static int threadCount;
public static void main(String[] args) throws InterruptedException {
list.add(firstElement);
list.add(secondElement);
System.out.println("how many threads");
Scanner sc = new Scanner(System.in);
threadCount = sc.nextInt();
Main exa = new DefaultMain();
exa.sum(count, threadCount, firstElement, secondElement);
}
#Override
public List<Integer> sum(int count, int threadCount, int firstElement, int secondElement) {
synchronized(this.list) {
for (int i = 0; i < DefaultMain.threadCount; i++) {
new Thread(new DefaultSum()).start();
}
return list;
}
}}
I tried running this program multiple times, however, it seems that the list is not updated after first two elements are added. Seems that methods getHowMany() and getList() work fine, I'm not sure what could be wrong, I'll appreciate any answer, this problem has been bugging me for some time now.
Edit: I'll paste what I get in console
Edit2: tried changing some bits, but it does not work at all.
how many threads
4
[0, 1]
[0, 1]
[0, 1]
[0, 1]
You just need to create a single thread Executor and then from any thread call execute() with the operations you need to do on the list in a Runnable provided as the only parameter. Here is what it looks like with a lambda.
ExecutorService service = Executors.newSingleThreadExecutor();
service.execute(() -> {
int size = list.size();
list.add(list.get(size - 1) + list.get(size - 2));
});
As the JavaDoc (https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newSingleThreadExecutor--) states "Creates an Executor that uses a single worker thread operating off an unbounded queue...Tasks are guaranteed to execute sequentially, and no more than one task will be active at any given time."
I have two ArrayLists.
List of dates
List of respective data.
Both are synchronized. I sometimes have more than one data on a same date. I need to create two lists: unique dates and the data (averaged) respectively. So far, I have tried the following methods
int i = 1;
for(int it =0; it < predatetime.size() - 1; it++){
//Compare each element with the next one
if(predatetime.get(it+1) == predatetime.get(it)){
i++;
weight = preweight.get(it+1) + weight;
//If equal, add weights and increment a divisor for averaging
}
else { //if not equal, add to the new lists
if(it == predatetime.size() - 2){ //if the last element is not equal to its previous one, just add it to the list
newDateTime.add(predatetime.get(it+1));
newWeight.add(preweight.get(it+1));
break;
}
weight = weight / i;
newDateTime.add(predatetime.get(it));
newWeight.add(weight);
weight = preweight.get(it+1); //re-initialize variables
i = 1;
}
if(it == predatetime.size() - 2){
weight = weight / i;
newDateTime.add(predatetime.get(it));
newWeight.add(weight);
}
}
There are a lot of problems with this code.
If the list has only one element, it fails. (I know I can write 2 more lines to care of this). Is there a better way to do this?
I know there are similar questions on this website, but still I'm unable to resolve the problem.
This is the full solution
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
public class CustomList {
public static void main(String[] args) {
ArrayList<String> date = new ArrayList<>();
date.add("1");
date.add("2");
date.add("2");
date.add("3");
System.out.println(date);
ArrayList<Integer> value = new ArrayList<>();
value.add(1);
value.add(2);
value.add(4);
value.add(3);
System.out.println(value);
new MyCls().createList(date, value);
}
}
class MyCls {
ArrayList uniqueDate = new ArrayList<String>();
ArrayList averageValue = new ArrayList<Integer>();
LinkedHashMap store = new LinkedHashMap<String, CountEntry>();
class CountEntry {
int value;
int count;
CountEntry() {
}
CountEntry(int v, int c) {
value = v;
count = c;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
public void createList(ArrayList<String> date, ArrayList<Integer> value) {
for (int i = 0; i < date.size(); i++) {
CountEntry tmp = (CountEntry) store.get(date.get(i));
if (tmp == null) {
store.put(date.get(i), new CountEntry(value.get(i), 1));
} else {
int tmpVal = tmp.getValue();
int tmpCount = tmp.getCount();
store.put(date.get(i), new CountEntry(value.get(i) + tmpVal, ++tmpCount));
}
}
ArrayList<String> uniqueDate = new ArrayList<String>(store.keySet());
ArrayList<CountEntry> tempAvgList = new ArrayList<CountEntry>(store.values());
for (CountEntry ce : tempAvgList) {
averageValue.add(ce.getValue() / ce.getCount());
}
System.out.println("Output");
System.out.println(uniqueDate);
System.out.println(averageValue);
}
}
/*
OUTPUT Snap:
[1, 2, 2, 3]
[1, 2, 4, 3]
Output
[1, 2, 3]
[1, 3, 3]
*/
If you try to make your list elements unique why you not try to convert the list to set collection
Set<Foo> foo = new HashSet<Foo>(myList);
Why not create a Map instead with the dates as the key and have the value as a list. This will allow you to keep the dates unique, at the same allow you to have your data as a list.
Map<String, ArrayList<myData>> myMap = new HashMap<String, ArrayList<myData>>();
Then you can just find if your key exists, if it does add it to the array list by using the key to identify the correct list. If it doesnt exist it, add it to the map
Thanks to #Rambler and #JulianGurung, I created a HashMap and it works
HashMap<Integer, Float> hm = new HashMap<Integer,Float>();
int occurance = 0;
float weight = 0;
hm.put(predatetime.get(0), 0f); //initialize with the first value
for(Map.Entry m : hm.entrySet()){
for( int it = 0; it < predatetime.size(); it++){
if(m.getKey() == predatetime.get(it)){
weight = (Float) m.getValue() + preweight.get(it); //Sum all the same data in order to avg later
hm.put(predatetime.get(it), weight);
occurance++;
}
else{ //if it is not equal, add the new element to the map
hm.put(predatetime.get(it), preweight.get(it));
}
}
weight = weight / occurance;
hm.put((Integer) m.getKey(), weight);
weight = 0;
occurance = 0;
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
Here is my example - pick random number from 1-20, then from 2-21, 3-22 and so on, while
excluding previous picks. I am new to Java, and doing something wrong.
import java.util.Random;
import java.util.ArrayList;
import java.util.List;
public class RandomGenerator {
static int temp;
public static void main(String[] args) {
List<Integer> randomNumberArray = new ArrayList<Integer>();
Random RandomNumber = new Random();
for (int i = 0; i<=20; i++)
{
temp = RandomNumber.nextInt(i+20) +1+i;
if (!randomNumberArray.contains(temp))
{
{
randomNumberArray.add(temp);
}
}
System.out.println(randomNumberArray);
}
There are a couple of things to go over.
1) If your number sees that there is a duplicate then it will skip it and continue with the next number, for example if you run it 5 times and it finds a duplicate once, then the resulting list of numbers will have only 4 numbers not 5! since it skipped one. (Not sure if this is what you wanted or not)
2) Your randomly generated number doesn't grow the way you expect it to grow.
For example: At the sixth iteration over the loop your random number will generate as:
RandomNumber.nextInt(25) +6;
That means that the number range there isn't 6-26 but 6-30!
Because: nextInt will return an int between 0 and 24 and then that int is added another 6 to it.
EDIT :
To tackle your first problem you can continue to generate numbers until you generate one that is not a duplicate for that single cycle of the for loop.
For this you can utilize the do-while loop so that it executes the number generation at least once before checking whether the number is a duplicate within the for loop.
So you can adjust your for loop from:
for (int i = 0; i<=20; i++)
{
temp = RandomNumber.nextInt(20) +1+i;
if (!randomNumberArray.contains(temp))
{
{
randomNumberArray.add(temp);
}
}
System.out.println(randomNumberArray);
}
into:
for (int i = 0; i<=20; i++)
{
do {
temp = RandomNumber.nextInt(20) +1+i;
} while (randomNumberArray.contains(temp));
randomNumberArray.add(temp);
System.out.println(randomNumberArray);
}
Notice that the check in the while expression is the opposite (does not have the exclamation mark) of what was in the if expression in the for loop before, since we do want to continue generating new random numbers while our numbers are duplicates.
And since we are still looping within that one cycle of the for loop, it will always generate the number with the appropriate value of i which was set for that for cycle.
You aren't excluding previous picks. Something like this will print twenty random numbers (e.g. all random numbers from 1-20).
public static void main(String[] args) {
java.util.Set<Integer> picked = new TreeSet<Integer>();
Random rand = new Random();
while (picked.size() < 20) {
int temp = 1+rand.nextInt(20);
if (picked.contains(temp)) {
continue;
}
picked.add(temp);
System.out.println(temp);
}
}
I'm not sure I understand your "stepping" idea, but add this for temp and it will do that too -
int temp = 1+picked.size()+rand.nextInt(20+picked.size());
Since the range of allowed elements isn't too big, you can also hold the pool of all possible numbers and pick one of them. You can use e.g. RandomSet from this answer.
import java.util.*;
import java.lang.*;
/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
static class RandomSet<E> extends AbstractSet<E> {
List<E> dta = new ArrayList<E>();
Map<E, Integer> idx = new HashMap<E, Integer>();
public RandomSet() {
}
public RandomSet(Collection<E> items) {
for (E item : items) {
idx.put(item, dta.size());
dta.add(item);
}
}
#Override
public boolean add(E item) {
if (idx.containsKey(item)) {
return false;
}
idx.put(item, dta.size());
dta.add(item);
return true;
}
/**
* Override element at position <code>id</code> with last element.
* #param id
*/
public E removeAt(int id) {
if (id >= dta.size()) {
return null;
}
E res = dta.get(id);
idx.remove(res);
E last = dta.remove(dta.size() - 1);
// skip filling the hole if last is removed
if (id < dta.size()) {
idx.put(last, id);
dta.set(id, last);
}
return res;
}
#Override
public boolean remove(Object item) {
#SuppressWarnings(value = "element-type-mismatch")
Integer id = idx.get(item);
if (id == null) {
return false;
}
removeAt(id);
return true;
}
public E get(int i) {
return dta.get(i);
}
public E pollRandom(Random rnd) {
if (dta.isEmpty()) {
return null;
}
int id = rnd.nextInt(dta.size());
return removeAt(id);
}
#Override
public int size() {
return dta.size();
}
#Override
public Iterator<E> iterator() {
return dta.iterator();
}
}
public static void main (String[] args) throws java.lang.Exception
{
RandomSet<Integer> rs = new RandomSet<Integer>();
for (int i = 0; i < 20; ++i) {
rs.add(i);
}
int count = 50;
Random r = new Random();
for (int i = 0; i < count; i++) {
System.out.println(rs.pollRandom(r));
rs.remove(i);
rs.add(i + 20);
}
}
}
Using the smart structure the overall time complexity is O(N + K), where N is the number of requested polls and K is the size of the pool.
Running Ideone example : http://ideone.com/Sfltr7
The trick here is to use Collections.shuffle(List list):
List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20);
Collections.shuffle(list);
System.out.println(list);
The progressive version goes something like this:
// Wrap it in an ArrayList so I can modify it.
List<Integer> list = new ArrayList(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20));
for (int i = 21; i < 25; i++) {
System.out.println(list);
// Shuffle it.
Collections.shuffle(list);
// Grab one.
Integer take = list.get(0);
list.remove(take);
System.out.println("Took " + take);
// Add my new candidate.
list.add(i);
}
Or you could go the whole hog and make it an Iterable:
public static class CreepingRandom implements Iterable<Integer> {
// The starting list.
private final List<Integer> start;
// How many steps to add.
private final int steps;
// What int to start adding.
private final int from;
public CreepingRandom(int initialSize, int from, int steps) {
// Make my start list.
start = new ArrayList<Integer>(initialSize);
// Fill it.
for (int i = 1; i <= initialSize; i++) {
start.add(i);
}
// Remember where to start from.
this.from = from;
// Remember how many steps.
this.steps = steps;
}
#Override
public Iterator<Integer> iterator() {
return new CreepingIterator();
}
private class CreepingIterator implements Iterator<Integer> {
// Track how many I've delivered.
int delivered = 0;
// The next number to add.
int add = from;
// My current list.
final ArrayList<Integer> list = new ArrayList(start);
#Override
public boolean hasNext() {
return delivered < steps;
}
#Override
public Integer next() {
// Shuffle it.
Collections.shuffle(list);
// Pull one out.
Integer next = list.get(0);
// Add my new one in.
list.set(0, add++);
// Count them.
delivered += 1;
return next;
}
}
}
public void test() {
for (Integer i : new CreepingRandom(20, 21, 100)) {
System.out.println(i);
}
}
private class CreepingIterator implements Iterator<Integer> {
// Track how many I've delivered.
int delivered = 0;
// The next number to add.
int add = from;
// My current list.
final ArrayList<Integer> list;
CreepingIterator() {
// Copy the start list - Use LinkedList for efficiency of add and removeFirst.
list = new ArrayList(start);
}
#Override
public boolean hasNext() {
return delivered < steps;
}
#Override
public Integer next() {
// Shuffle it.
Collections.shuffle(list);
// Pull one out.
Integer next = list.get(0);
// Add my new one in.
list.set(0, add++);
// Count them.
delivered += 1;
return next;
}
}
}
public void test() {
for (Integer i : new CreepingRandom(20, 21, 100)) {
System.out.println(i);
}
}
Hi I have implemented a method that calculated the Mode value from an array of millions of elements (integers).
I am now comparing a sequential version to a (supposed to be ) improved version that makes use of the Executor Service... unfortunately the performance is not as good as expected:
Sequentiallly iterating hashMap (version 0)
#size #time #memory
10000000 13772ms 565mb
20000000 35355ms 1135mb
30000000 45879ms 1633mb
Assigning jobs to a Service Executor (version 2)
#size #time #memory
10000000 16186ms 573mb
20000000 34561ms 1147mb
30000000 54792ms 1719mb
The code for the Executor Service is as follows:
/* Optimised-Threaded Method to calculate the Mode */
private int getModeOptimisedThread(int[] mybigarray){
System.out.println("calculating mode (optimised w/ ExecutorService)... ");
int mode = -1;
//create an hashmap to calculating the frequencies
TreeMap<Integer, Integer> treemap = new TreeMap<Integer, Integer>();
//for each integer in the array, we put an entry into the hashmap with the 'array value' as a 'key' and frecuency as 'value'.
for (int i : mybigarray) {
//we check if that element already exists in the Hashmap, by getting the element with Key 'i'
// if the element exists, we increment the frequency, otherwise we insert it with frecuency = 1;
Integer frequency = treemap.get(i);
int value = 0;
if (frequency == null){ //element not found
value = 1;
}
else{ //element found
value = frequency + 1;
}
//insert the element into the hashmap
treemap.put(i, value);
}
//Look for the most frequent element in the Hashmap
int maxCount = 0;
int n_threads = Runtime.getRuntime().availableProcessors();
ExecutorService es = Executors.newFixedThreadPool(n_threads);
//create a common variable to store maxCount and mode values
Result r = new Result(mode, maxCount);
//set the umber of jobs
int num_jobs = 10;
int job_size = treemap.size()/num_jobs;
System.out.println("Map size "+treemap.size());
System.out.println("Job size "+job_size);
//new MapWorker(map, 0, halfmapsize, r);
int start_index, finish_index;
List<Callable<Object>> todolist = new ArrayList<Callable<Object>>(num_jobs);
//assign threads to pool
for (int i=0; i<num_jobs; i++)
{
start_index=i*job_size;
finish_index = start_index+job_size;
System.out.println("start index: "+start_index+". Finish index: "+finish_index);
todolist.add(Executors.callable(new MapWorker(treemap.subMap(start_index, finish_index), r)));
}
try{
//invoke all will not return until all the tasks are completed
es.invokeAll(todolist);
} catch (Exception e) {
System.out.println("Error in the Service executor "+e);
} finally {
//finally the result
mode = r.getMode();
}
//return the result
return mode;
}
Any suggestion about the quality of the Executor Service's code?
Please suggest, it's the first time I implement the E.S.
Edit:
Worker
public class MapWorker implements Runnable{
private int index;
private int size;
private int maxCount;
private Result result;
private Map <Integer, Integer> map;
//Constructor
MapWorker( Map <Integer, Integer> _map, Result _result){
this.maxCount = 0;
this.result = _result;
map = _map;
}
public void run(){
for (Map.Entry<Integer, Integer> element : map.entrySet()) {
if (element.getValue() > result.getCount()) {
result.setNewMode(element.getKey(),element.getValue());
}
}
}
}
and Result class:
public class Result {
private int mode;
private int maxCount;
Result(int _mode, int _maxcount){
mode = _mode;
maxCount = _maxcount;
}
public synchronized void setNewMode(int _newmode, int _maxcount) {
this.mode = _newmode;
this.maxCount = _maxcount;
}
public int getMode() {
return mode;
}
public synchronized int getCount() {
return maxCount;
}
}
for each job, use separate Result object (without synchronization). When all jobs finish, chose result with maximum value.
int num_jobs = n_threads;
The chunk of the work is being done while computing the frequencies. That will significantly dominate any benefits of parallelism you will get by trying to update the results. You need to work on parallelizing the computation of the mode by each worker computing frequencies locally before updating a global frequency at the end. You can consider using AtomicInteger to store the mode in the global store to ensure thread safety. Once the frequencies have been computed, you can compute the mode sequentially at the end as it will have much lower computation cost to traverse the map sequentially.
Something like the following should work better:
EDIT: modified the updateScore() method to fix a data race.
private static class ResultStore {
private Map<Integer, AtomicInteger> store = new ConcurrentHashMap<Integer, AtomicInteger>();
public int size() {
return store.size();
}
public int updateScore(int key, int freq) {
AtomicInteger value = store.get(key);
if (value == null) {
store.putIfAbsent(key, new AtomicInteger(0));
value = store.get(key);
}
return value.addAndGet(freq);
}
public int getMode() {
int mode = 0;
int modeFreq = 0;
for (Integer key : store.keySet()) {
int value = store.get(key).intValue();
if (modeFreq < value) {
modeFreq = value;
mode = key;
}
}
return mode;
}
}
private static int computeMode(final int[] mybigarray) {
int n_threads = Runtime.getRuntime().availableProcessors();
ExecutorService es = Executors.newFixedThreadPool(n_threads);
final ResultStore rs = new ResultStore();
//set the number of jobs
int num_jobs = 10;
int job_size = mybigarray.length / num_jobs;
System.out.println("Map size " + mybigarray.length);
System.out.println("Job size " + job_size);
List<Callable<Object>> todolist = new ArrayList<Callable<Object>>(num_jobs);
for (int i = 0; i < num_jobs; i++) {
final int start_index = i * job_size;
final int finish_index = start_index + job_size;
System.out.println("Start index: " + start_index + ". Finish index: " + finish_index);
todolist.add(Executors.callable(new Runnable() {
#Override
public void run() {
final Map<Integer, Integer> localStore = new HashMap<Integer, Integer>();
for (int i = start_index; i < finish_index; i++) {
final Integer loopKey = mybigarray[i];
Integer loopValue = localStore.get(loopKey);
if (loopValue == null) {
localStore.put(loopKey, 1);
} else {
localStore.put(loopKey, loopValue + 1);
}
}
for (Integer loopKey : localStore.keySet()) {
final Integer loopValue = localStore.get(loopKey);
rs.updateScore(loopKey, loopValue);
}
}
}));
}
try {
//invoke all will not return until all the tasks are completed
es.invokeAll(todolist);
} catch (Exception e) {
System.out.println("Error in the Service executor " + e);
}
return rs.getMode();
}
i have a task where i need to find the mode of an array. which means i am looking for the int which is most frequent. i have kinda finished that, but the task also says if there are two modes which is the same, i should return the smallest int e.g {1,1,1,2,2,2} should give 1 (like in my file which i use that array and it gives 2)
public class theMode
{
public theMode()
{
int[] testingArray = new int[] {1,1,1,2,2,2,4};
int mode=findMode(testingArray);
System.out.println(mode);
}
public int findMode(int[] testingArray)
{
int modeWeAreLookingFor = 0;
int frequencyOfMode = 0;
for (int i = 0; i < testingArray.length; i++)
{
int currentIndexOfArray = testingArray[i];
int frequencyOfEachInArray = howMany(testingArray,currentIndexOfArray);
if (frequencyOfEachInArray > frequencyOfMode)
{
modeWeAreLookingFor = currentIndexOfArray;
frequencyOfMode = modeWeAreLookingFor;
}
}
return modeWeAreLookingFor;
}
public int howMany(int[] testingArray, int c)
{
int howManyOfThisInt=0;
for(int i=0; i < testingArray.length;i++)
{
if(testingArray[i]==c){
howManyOfThisInt++;
}
}
return howManyOfThisInt;
}
public static void main(String[] args)
{
new theMode();
}
}
as you see my algorithm returns the last found mode or how i should explain it.
I'd approach it differently. Using a map you could use each unique number as the key and then the count as the value. step through the array and for each number found, check the map to see if there is a key with that value. If one is found increment its value by 1, otherwise create a new entry with the value of 1.
Then you can check the value of each map entry to see which has the highest count. If the current key has a higher count than the previous key, then it is the "current" answer. But you have the possibility of keys with similar counts so you need to store each 'winnning' answer.
One way to approach this is to check each map each entry and remove each entry that is less than the current highest count. What you will be left with is a map of all "highest counts". If you map has only one entry, then it's key is the answer, otherwise you will need to compare the set of keys to determine the lowest.
Hint: You're updating ModeWeAreLookingFor when you find a integer with a strictly higher frequency. What if you find an integer that has the same frequency as ModeWeAreLookingFor ?
Extra exercice: In the first iteration of the main loop execution, you compute the frequency of '1'. On the second iteration (and the third, and the fourth), you re-compute this value. You may save some time if you store the result of the first computation. Could be done with a Map.
Java code convention states that method names and variable name should start with a lower case character. You would have a better syntax coloring and code easier to read if you follow this convention.
this might work with a little modification.
http://www.toves.org/books/java/ch19-array/index.html#fig2
if ((count > maxCount) || (count == maxCount && nums[i] < maxValue)) {
maxValue = nums[i];
maxCount = count;
}
since it seems there are no other way, i did a hashmap after all. i am stuck once again in the logics when it comes to comparing frequencys and and the same time picking lowest integer if equal frequencys.
public void theMode()
{
for (Integer number: intAndFrequencyMap.keySet())
{
int key = number;
int value = intAndFrequencyMap.get(number);
System.out.println("the integer: " +key + " exists " + value + " time(s).");
int lowestIntegerOfArray = 0;
int highestFrequencyOfArray = 0;
int theInteger = 0;
int theModeWanted = 0;
if (value > highestFrequencyOfArray)
{
highestFrequencyOfArray = value;
theInteger = number;
}
else if (value == highestFrequencyOfArray)
{
if (number < theInteger)
{
number = theInteger;
}
else if (number > theInteger)
{
}
else if (number == theInteger)
{
number = theInteger;
}
}
}
}
Completed:
import java.util.Arrays;
public class TheMode
{
//Probably not the most effective solution, but works without hashmap
//or any sorting algorithms
public TheMode()
{
int[] testingArray = new int[] {2,3,5,4,2,3,3,3};
int mode = findMode(testingArray);
System.out.println(Arrays.toString(testingArray));
System.out.println("The lowest mode is: " + mode);
int[] test2 = new int[] {3,3,2,2,1};
int mode2=findMode(test2);
System.out.println(Arrays.toString(test2));
System.out.println("The lowest mode is: " +mode2);
int[] test3 = new int[] {4,4,5,5,1};
int mode3 = findMode(test3);
System.out.println(Arrays.toString(test3));
System.out.println(The lowest mode is: " +mode3);
}
public int findMode(int[] testingArray)
{
int modeWeAreLookingFor = 0;
int frequencyOfMode = 0;
for (int i = 0; i < testingArray.length; i++)
{
int currentIndexOfArray = testingArray[i];
int countIntegerInArray = howMany(testingArray, currentIndexOfArray);
if (countIntegerInArray == frequencyOfMode)
{
if (modeWeAreLookingFor > currentIndexOfArray)
{
modeWeAreLookingFor = currentIndexOfArray;
}
}
else if (countIntegerInArray > frequencyOfMode)
{
modeWeAreLookingFor = currentIndexOfArray;
frequencyOfMode = countIntegerInArray;
}
}
return modeWeAreLookingFor;
}
public int howMany(int[] testingArray, int c)
{
int howManyOfThisInt=0;
for(int i=0; i < testingArray.length;i++)
{
if(testingArray[i]==c){
howManyOfThisInt++;
}
}
return howManyOfThisInt;
}
public static void main(String[] args)
{
new TheMode();
}
}
Glad you managed to solve it. As you will now see, there is more than one way to approach a problem. Here's what I meant by using a map
package util;
import java.util.HashMap;
import java.util.Map;
public class MathUtil {
public static void main(String[] args) {
MathUtil app = new MathUtil();
int[] numbers = {1, 1, 1, 2, 2, 2, 3, 4};
System.out.println(app.getMode(numbers));
}
public int getMode(int[] numbers) {
int mode = 0;
Map<Integer, Integer> numberMap = getFrequencyMap(numbers);
int highestCount = 0;
for (int number : numberMap.keySet()) {
int currentCount = numberMap.get(number);
if (currentCount > highestCount) {
highestCount = currentCount;
mode = number;
} else if (currentCount == highestCount && number < mode) {
mode = number;
}
}
return mode;
}
private Map<Integer,Integer> getFrequencyMap(int[] numbers){
Map<Integer, Integer> numberMap = new HashMap<Integer, Integer>();
for (int number : numbers) {
if (numberMap.containsKey(number)) {
int count = numberMap.get(number);
count++;
numberMap.put(number, count);
} else {
numberMap.put(number, 1);
}
}
return numberMap;
}
}