I am trying to write as few lines as possible.
What would be the best way to re-write this in Java? (say we have a "public enum A")
I want to have a way of writing "if something is not null, return it, otherwise, keep going".
I looked into Optional, but Optional.of(...).ifPresent( v -> return v;) does not work, although I wish it did.
Also, if you are asking why I am changing the array inside a for-loop, you can consider that there are multiple initial arrays and I need to test them each.
public A getAValue() {
int[] arr = new int[7];
A returnValue = null;
for (int i=0; i<10; i++) {
//change arr
returnValue = checkSomeCondition(arr);
if (returnValue != null) {
return returnValue;
}
//change arr again
returnValue = checkSomeCondition(arr);
if (returnValue != null) {
return returnValue;
}
//change arr yet again
returnValue = checkSomeCondition(arr);
if (returnValue != null) {
return returnValue;
}
}
return A.UNKNOWN;
}
public A checkSomeCondition(int[] arr) {
if (arr[0]==arr[1]) {
return arr[0]==2 ? A.VALUE_1 : A.VALUE_2;
}
return null;
}
Q: I looked into Optional, but Optional.of(...).ifPresent( v -> return v;) does not work, although I wish it did
Optional::ifPresent works, but different than intended. The return is within the method implementation of the Consumer. Moreover, the Consumer doesn't return anything, the method return type is void.
Q: I am trying to write as few lines as possible.
You achieve what you want with the help of a predefined set of the array suppliers Supplier<int[]> and another for-loop inside the already existing one with a number of iterations the same as a number of conditions.
List<Supplier<int[]>> arrays = new ArrayList<>();
arrays.add(() -> firstArraySource());
arrays.add(() -> secondArraySource());
...
for (...) { // your initial loop
for (Supplier<int[]> arraySupplier: arrays) { // iterate through Suppliers
arr = arraySupplier.get(); // get an array (here is the evaluation)
returnValue = checkSomeCondition(arr); // getting the 'A' value
if (returnValue != null) { // returnin if not null
return returnValue;
}
}
}
The advantage of this approach is that if the sources of arrays are ex. from the database, they won't be called before they are actually needed since they are wrapped in the Suppliers. The calculaiton happens when Supplier::get is called.
Not clear what kind of test your doing or how you are alteringyour arrays but this may be possible:
This should ignore all null return values and only return the first successful test result.
If no successes, a default return object must be supplied.
enum A {
A_VALUE_1, A_VALUE_2, A_UNKNOWN
};
List<Object[]> testArrays = new ArrayList<>();
testArrays.add(new int[] { 1, 2, 3 });
testArrays.add(new int[] { 3, 4, 5 });
testArrays.add(new int[] { 2, 2, 6 });
A res =
// stream the set of arrays
testArrays.stream()
// apply each set in order to the method
// replacing the array under test with the
// method result
.map(arr->checkSomeCondition(arr))
// filter out any null results
.filter(result->result!=null)
// get the first non-null result
.findFirst()
// return the result or some default answer if all
// results were null.
.orElseGet(()->A.A_UNKNOWN);
System.out.println(res);
With the supplied data, prints
A_VALUE_1
Your test method
public A checkSomeCondition(int[] arr) {
if (arr[0] == arr[1]) {
return arr[0] == 2 ? A.A_VALUE_1 : A.A_VALUE_2;
}
return null;
}
The down side is it requires you to supply an array of arrays where subsequent ones are to be used if the previous test fails. You may be able to adapt the concept to your requirements.
Use Optional.ofNullable instead of Optional.of as the latter can't be used for possibly null values. That would work, as well as delegating that task to checkSomeCondition function:
public Optional<A> checkSomeCondition(int[] arr) {
if (arr[0] == arr[1]) {
return Optional.<A>of(arr[0]==2 ? A.VALUE_1 : A.VALUE_2);
}
return Optional.<A>empty();
}
...and then checking the presence of value in getAValue.
The condition can then be checked in a loop, i.e.
public A getAValue() {
int[] arr = new int[7];
final int maxChecks = 10;
Optional<A> returnValue = Optional.<A>empty();
for (int i = 0; i < 10; i++) {
int j = 0;
while (!returnValue.isPresent() && j < maxChecks) {
returnValue = checkSomeCondition(arr);
j++;
}
return returnValue.get();
}
return A.UNKNOWN;
}
Related
I have a array list contains thousands of data.
For Example:
List<String> custNames = new ArrayList<String>();
custNames.add("John");
custNames.add("Tom");
custNames.add("Bart");
custNames.add("Tim");
custNames.add("Broad");
Now I want to get count of names only starting with 'T'. I used looping mechanism for my solution.
List<String> filterNames = new ArrayList<String>();
String nameStarts="T";
for(int i=0;i<custNames.size();i++)
{
if(custNames.get(i).toLowerCase().startsWith(nameStarts.toLowerCase()))
{
filterNames.add(custNames.get(i));
}
}
System.out.println(filterNames.size());
But I have very large collection of data in this custNames list.
Is there any different solution without using loop?
Thanks.
There is very good solution from Java 8 for your problem.
Try this,
long filterNameCount = custNames
.stream()
.parallel()
.filter((s) -> s.startsWith(nameStarts.toLowerCase()))
.count();
System.out.println(filterNameCount);
If you are open to using a third-party library, there are a few interesting options you could use with Eclipse Collections.
If you use the ArrayList as you have it above, you can use the LazyIterate utility as follows:
int count = LazyIterate.collect(custNames, String::toLowerCase)
.countWith(String::startsWith, nameStarts.toLowerCase());
Assert.assertEquals(2, count);
If you use the Eclipse Collections replacement for ArrayList, you can use the rich functional protocols available directly on MutableList:
MutableList<String> custNames =
Lists.mutable.with("John", "Tom", "Bart", "Tim", "Broad");
String nameStarts= "T";
int count = custNames.asLazy()
.collect(String::toLowerCase)
.countWith(String::startsWith, nameStarts.toLowerCase());
System.out.println(count);
Assert.assertEquals(2, count);
The serial API in Eclipse Collections is eager-by-default, which is why I called asLazy() first. The collect method would otherwise create another MutableList.
If you benchmark your code with your full set of data, the following parallel version of the code may be more performant:
MutableList<String> custNames =
Lists.mutable.with("John", "Tom", "Bart", "Tim", "Broad");
String nameStarts= "T";
int processors = Runtime.getRuntime().availableProcessors();
int batchSize = Math.max(1, custNames.size() / processors);
ExecutorService executor = Executors.newFixedThreadPool(processors);
int count = custNames.asParallel(executor, batchSize)
.collect(String::toLowerCase)
.countWith(String::startsWith, nameStarts.toLowerCase());
executor.shutdown();
Assert.assertEquals(2, count);
The asParallel() API in Eclipse Collections is lazy-by-default. The API forces you to pass in a an ExecutorService and an int batchSize. This gives you complete control over the parallelism.
You can also use the Stream API with all MutableCollections in Eclipse Collections because they extend java.util.Collection.
Note: I am a committer for Eclipse Collections.
You could also use a tree storage : it would very efficient for this kind of search. If you are stucked with a list the previous answered is a way to do.
remove all the items which dont start with "T" like this:
custNames.removeIf(p->!p.startsWith("T"));
you can make a copy out of your list and remove items not starting with "T".
First, you can shorten your initialization with Arrays.asList(T); Second, I would use a simple loop to build a table of counts once and then use that to determine the subsequent queries. Something like,
List<String> custNames = new ArrayList<String>(Arrays.asList("John", "Tom",
"Bart", "Tim", "Broad"));
int[] counts = new int[26];
for (String name : custNames) {
char ch = Character.toLowerCase(name.charAt(0));
counts[ch - 'a']++;
}
for (int i = 0; i < counts.length; i++) {
if (counts[i] > 0) {
System.out.printf("There are %d words that start with %c%n",
counts[i], (char) ('a' + i));
}
}
Which outputs
There are 2 words that start with b
There are 1 words that start with j
There are 2 words that start with t
Or, in the specific case - counts['t' - 'a'] is the count of words starting with t.
If you have more or less static list and perform search operation often you can sort your list or use TreeMap.
Also you don't need to create new list and get its size then. You can simply create a counter variable and increment it.
You can create your own sorting and finding implementation.
Consider the following:
public class ContainingArrayList<E> extends ArrayList<E> {
private Comparator<E> comparator;
public ContainingArrayList(Comparator<E> comparator) {
this.setComparator(comparator);
}
#Override
public boolean add(E e) {
// If the collection is empty or the new element is bigger than the last one, append it to the end of the collection
if(size() == 0 || comparator.compare(e, get(size()-1)) >= 0)
return super.add(e);
else {
for (int i = 0; i < size(); i++) {
int result = comparator.compare(e, get(i));
// If the new element is bigger than the current element, continue with the next element
if (result > 0) continue;
// If the new element is equal to the current element, no need to insert (you might insert of course)
if (result == 0) return false;
// Otherwise the new element is smaller than the current element, so insert it between the previous and the current element
super.add(i, e);
return true;
}
return super.add(e);
}
}
public E get(E containingElement) {
int start = 0;
int end = size()-1;
// If the element is the first one, return the first element
if(comparator.compare(containingElement, super.get(start)) == 0)
return super.get(start);
// If the element is the last one, return the last element
if(comparator.compare(containingElement, super.get(end)) == 0)
return super.get(end);
// Otherwise do a binary search
while(start != end) {
// Get the element between start and end positions
E mid = super.get(start + (end/2));
// Compare the two elements
int result = comparator.compare(containingElement, mid);
// If the middle element compared to the containing element is equal, return the middle element
if(result == 0) {
return mid;
}
// If the containing element is smaller than the middle, halve the end position
else if(result < 0) {
end = start + (end/2);
}
// If the containing element is bigger than the middle, set the start position to the middle position
else if(result > 0) {
start = start + (end/2);
}
}
return null;
}
public Comparator<E> getComparator() {
return comparator;
}
public void setComparator(Comparator<E> comparator) {
this.comparator = comparator;
}
}
The custom comparator is used to sort the elements and to find the element that starts with a specific character. This means that you can change the comparator implementation for your needs at any time or you can create a more dynamic finding solution.
Test:
public class SortFindTest {
public SortFindTest() {
ContainingArrayList<String> t = new ContainingArrayList<String>(new MyComparator());
t.add("John");
t.add("Tom");
t.add("Bart");
t.add("Tim");
t.add("Broad");
System.out.println(t.get("T"));
}
class MyComparator implements Comparator<String> {
#Override
public int compare(String o1, String o2) {
int o1c = o1.charAt(0);
int o2c = o2.charAt(0);
if(o1c == o2c)
return 0;
if(o1c > o2c)
return 1;
return -1;
}
}
public static void main(String[] args) {
new SortFindTest();
}
}
I'm not sure if this would be faster than Java 8 Stream API but it worth a try.
If the order in which the items are stored does not matter, you could store the names in a HashMap, where the first character of each name is the key, and an ArrayList of names with that first character are the values. And then all you need to do, assuming the HashMap is named customerList, is customerList.get("T").size().
Initializing HashList and Adding Customers
HashMap<Character, ArrayList<String>> customerList = new HashMap<Character, ArrayList<String>>();
int NUM_ALPHABETS = 26;
int ascii_char = 97;
for(int i = 0; i < NUM_ALPHABETS; i++){
char c = (char) ascii_char;
customerList.add(c, new ArrayList<String>());
ascii_char++;
}
customerList.get("t").add("Tony");
customerList.get("a").add("Alice");
customerList.get("b").add("Ben");
Getting Number of Customers Starting with "t"
int num_t = customerList.get("t").size();
I made a method which finds a value in my ArrayList. I also copied this method so I could use it for my array but certain things such as the get and size don't work. I'm unsure how I'm supposed to restructure it.
public Product findProduct(String givenProduct) throws IllegalProductCodeException {
IllegalProductCodeException notFoundMessage
= new IllegalProductCodeException("Product was not found");
int size = rangeOfProducts.length;
int i = 0;
boolean productFound = false;
while (!productFound && i < size) { //While book hasn't been found and i is less than the size of the array
productFound = rangeOfProducts.get(i).getProductCode().equals(givenProduct);
//Checks whether the given value in the array's reference is equal to the given reference entered
i++; //if not then add 1
}
if (productFound) {
return rangeOfProducts.get(i - 1);
} else {
throw notFoundMessage;
}
}
The array alternative to .get(i) will be [i] and the alternative to .size() will be .length.
for (Product product : products) {
if (product.getProductCode().equals(givenProduct)) {
return product;
}
}
throw new IllegalProductCodeException("Product was not found");
Edit: Java 5's enhanced for loop is equivalent to
for (Iterator<Product> iter=products.iterator(); iter.hasNext(); ) {
Product product = iter.next();
I am stuck.
The following function is supposed to return currVm, an integer. But if I make a return I will break the loop and next time when this function is called,the same process will begin again.
What shall I do, so that I continue from where I left off ? I tried making static variables but I that didn't help me.
#Override
public int getNextAvailableVm() {
Set<String> dataCenters = confMap.keySet();
for (String dataCenter : dataCenters) {
LinkedList<DepConfAttr> list = confMap.get(dataCenter);
Collections.sort(list, new MemoryComparator());
int size = list.size() - 1;
int count = 0;
while(size >= 0) {
DepConfAttr dca = (DepConfAttr)list.get(count);
int currVm = dca.getVmCount();
int c = 0;
while(c <= currVm) {
allocatedVm(currVm);
c++;
return currVm;
}
count++;
size--;
}
}
return 0;
}
The for-each loop assigns a new data center that acts as a key for the confMap.The list that I get as a value, is sorted.Then a loop is run till it escapes its size.Inside this while loop, another while loop is run from where a function named allocatedVm of the inherited class is called. A parameter named currVm is passed to it.
This is the variable that I need to return. What shall I do to return this variable ? I have to start from I left off. I mean the next call should appear to be the next step, whatever it was, while executing the loop.
Add List<Integer> object to your class, and change your method as follows:
private Iterator<Integer> availableVms = null;
#Override
public int getNextAvailableVm() {
if (availableVms != null) {
if (availableVms.hasNext()) {
return availableVms.next();
}
return 0;
}
List<Integer> tmp = new ArrayList<Integer>();
Set<String> dataCenters = confMap.keySet();
for (String dataCenter : dataCenters) {
LinkedList<DepConfAttr> list = confMap.get(dataCenter);
Collections.sort(list, new MemoryComparator());
int size = list.size() - 1;
int count = 0;
while(size >= 0) {
DepConfAttr dca = (DepConfAttr)list.get(count);
int currVm = dca.getVmCount();
int c = 0;
while(c <= currVm) {
allocatedVm(currVm);
c++;
tmp.add(currVm);
}
count++;
size--;
}
}
availableVms = tmp.iterator();
return availableVms.hasNext() ? availableVms.next() : 0;
}
The idea is to pre-generate the entire list, and store its iterator for future use. Before entering the method you check if the availableVms iterator has been prepared. If it has been prepared, grab the next item off of it if it's available; otherwise, return zero.
If the list has not been prepared yet, run your algorithm, and add the results to a temporary list tmp. Once the list is ready, grab its iterator, and use it for subsequent invocations.
I have two arraylist name preBusinessList, businessList. In business List I have data from server, and in preBusinessList is the local one. In lists I have id, count value Betterly demonstrate as below
Now I wanted to make a newBusinessList like this
How can I do it in java, please help me to solve this
Then I would use a map to do the merge using id as the key and convert it back to your list of (id,value) pairs
You can use:
Collections.sort(new ArrayList<...>(preBusinessList).addAll(businessList), comparator)
Where comparator is a class that implements Comparator interface (will be responsible for sorting as you wish)
assumming i understood your problem correctly (big if...):
also, i assume each element in the lists is a Pair - as it looks from your data (just a dumb wrapper class that holds 2 integers). if its some other class you'll need to adjust this code.
private Map<Integer,Integer> finalValues = new HashMap<Integer,Integer>();
for (Pair<Integer,Integer> entry : preBusinessList) {
finalValues.put(entry.getFirst(), entry.getSecond());
}
//2nd list overwrites values from 1st (anything not overwritten remains)
for (Pair<Integer,Integer> entry : businessList) {
finalValues.put(entry.getFirst(), entry.getSecond());
}
ArrayList<Pair<Integer,Integer>> finalList = new ArrayList<>();
for (Map.Entry<Integer,Integer> entry : finalValues) {
finalList.add(new Pair(entry.getKey(), entry.getValue());
}
//and now sort the list
Collections.sort(finalList, new Comparator<Pair<Integer,Integer>> {
int compare(Pair<Integer,Integer> a, Pair<Integer,Integer>b) {
return a.getFirst.compareTo(b.getFirst()); //compare by 1st number in pair only
}
});
Assuming something like:
public class Info {
public int id;
public int info;
}
You could merge them on the basis of wanting the keep the one with higher info field as follows:
// Assumes:
// - that the ArrayLists are sorted to have id in order going up
// - no repeated ids in a or in b (but same id can be in both a and b)
ArrayList<Info> merge(ArrayList<Info> a, ArrayList<Info> b) {
int aLength = a.size();
int bLength = b.size();
int ai = 0;
int bi = 0;
ArrayList<Info> result = new ArrayList<Info>();
while ((ai < aLength) && (bi < bLength))
Info aInfo = a.get(ai);
Info bInfo = b.get(bi);
if (aInfo.id == bInfo.id) {
if (aInfo.info >= bInfo.info) result.add(aInfo);
else result.add(bInfo);
ai++;
bi++;
}
else if (aInfo.id < bInfo.id) {
result.add(aInfo);
ai++;
}
else {
result.add(bInfo);
bi++;
}
}
// Add the remaining terms - only one of the loops will actually do anything
for (; ai<aiLength; ai++) {
result.add(a.get(ai));
}
for (; bi<biLength; bi++) {
result.add(b.get(bi));
}
}
Pseudocode :
Iterate over preBusinessList.
Fetch key and see if this key(1,2,3,4,5,6) exists in businesslist
If yes conitnue
Else If no, then add it to businesslist
for(Map.Entry<Integer, Integer> keyValue : preBusinessList.entrySet()) {
if(!businesslist.containsKey(keyValue.getKey())) {
businesslist.put(keyValue.getKey(), keyValue.getValue());
}
}
Updated Answer as per new requirements
boolean ifExists = false;
for(PlaceItems itemPreBusinessList : preBusinessList) {
ifExists = false;
for(PlaceItems itemBusinessList : businessList) {
if(itemBusinessList.businessId == itemPreBusinessList.businessId) {
// Already exists
ifExists = true;
break;
}
}
if(!isExists) {
businessList.add(itemPreBusinessList);
}
}
I'm trying to learn Java and basically my approach has been to take the procedural style I learned with python, and apply it to Java. So I never use classes and just put everything in a single class with many methods(which I just use as python functions). I think I've hit a problem, and need to bite the bullet and use classes, but I'm having trouble wrapping my head around how to do it.
To simplify my problem(ignore the poor design- it's just to illustrate the point), I have a program that takes a list and within a for loop does some math on each item(in this case adds 1 to the value of the list). I only want it to do work on 2 items on the list and then stop(in this example it's the first 2 items but in my real program it could be anywhere in the list). Here's the working code that is similar to how I'm already doing it:
No Classes:
public class LearningClasses {
public static void main(String[] args) {
int[] list = new int[]{1,2,3,4,5,6,7,8,9,10};
int[] data_list = new int[list.length];
for (int current_location = 0; current_location<list.length;current_location++) {
for (int i =0; i<100; i++){
if (check_size(data_list) == false ) {
break;
}
data_list[current_location] = (list[current_location]+1);
}
}
//its done now lets print the results
for (Integer item : data_list) {
System.out.println(item);
}
}
private static boolean check_size(int[] data_list) {
// TODO Auto-generated method stub
int count = 0;
for (int item : data_list) {
if (item != 0) {
count++;
if (count>=2) {
break;
}
}
}
if (count>=2) {
return false;
} else {
return true;
}
}
}
The problem with this code is although it works it's inefficient because it calculates the count on every iteration of the second for loop. In my program I cannot put anything above the first for loop but I can put anything below it, so I thought instead of doing the count every time maybe I could use a class to somehow maintain state and just increment the number as oppose to recalculating every time.
With classes:
public class LearningClassesCounter {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] list = new int[]{1,2,3,4,5,6,7,8,9,10};
int[] data_list = new int[list.length];
for (int current_location = 0; current_location<list.length;current_location++) {
//can only put commands in here. Nothing above.
Counter checker = new Counter(data_list);
System.out.println(checker.check_data());
for (int i =0; i<100; i++){
data_list[current_location] = (list[current_location]+1);
}
}
//its done now lets print the results
for (Integer item : data_list) {
System.out.println(item);
}
}
}
class Counter {
private int count; // current value
private boolean continue_or_not;
private int[] data_list;
// create a new counter with the given parameters
public Counter(int[] data_list) {
data_list = this.data_list;
count = 0;
continue_or_not = true;
}
public boolean check_data() {
// TODO Auto-generated method stub
int count = 0;
for (int item : data_list) {
if (item != 0) {
count++;
if (count>=3) {
break;
}
}
}
if (count>=3) {
return false;
} else {
return true;
}
}
// increment the counter by 1
public void increment() {
count++;
}
// return the current count
public int value() {
return count;
}
}
This doesn't work because it thinks the data_list is a null pointer(I know I'm declaring it null, but if I make it private int[] data_list = data_list it doesn't compile either). My ultimate goal is to have some kind of controls, in this case its limiting it to 2 items but I want to also add other limits like total value of al items cannot exceed X or cannot be lower than X and want to save CPU power by not having to do full calculations every time. So I think I need to be able to increment the values and then need to check that those increments haven't exceeded thresholds.
Can anyone help me understand what I'm doing wrong? Am I only wrong with syntax; or am I designing this wrong?
//can only put commands in here. Nothing above.
Counter checker = new Counter(data_list);
System.out.println(checker.check_data());
When you are calling checker.check_data(), its trying to parse through the data_list, but its empty. So, it throws a NullPointerException. The data_list is empty because inside your constructor, you may need to initialize like this this.data_list = data_list instead of data_list = this.data_list (here this.data_list has no reference so NULL)
If you avoid that call, the output will be 2,3,4,5,6,7,8,9,10,11.