I was given feedback that I need to improve my refactoring/eleminating code smells skills.
I need short exercises to detect and how-to improve the most comon code smells
with answers in java
example:
public class Calculator {
public long sum(int min, int max) {
long result = 0;
for (int i = min ; i <= max ; i++)
result += i;
return result;
}
public long sumOfSquares(int min, int max) {
long result = 0;
for (int i = min ; i <= max ; i++)
result += i * i;
return result;
}
}
and then the best/most convinent solution.
BTW, you could right away show me best solution for this repetition over there /\ maybe with use of operator lambda "->"
Thanks!
You could try merging both methods in one. Since both of them look like
public long sum(long min, long max) {
long result = 0;
for (int i = min ; i <= max ; i++)
result += someOperation(i);
return result;
}
you could allow user to provide some operation which will compute i, so it can be i or i+2 or i*i.
Such strategy can be implementation of LongUnaryOperator interface where user will need to implement long applyAsLong(long operand) method.
So instead of two methods you can have one which can look like
public static long sum(long min, long max, LongUnaryOperator mapper) {
long result = 0;
for (long i = min ; i <= max ; i++)
result += mapper.applyAsLong(i);
return result;
}
and you could use it like
sum(1, 4, i -> i * i)//sum of squares
i->i*i is lambda expression which implements functional interface LongUnaryOperator and provides implementation of its abstract applyAsLong method which will be used in our code. In other words it will map i to i*i.
more usage examples:
sum(1, 4, i -> 2 * i)//sum of doubled values
sum(1, 4, i -> i)//sum of original values
//i->i can be also returned with `LongUnaryOperator.identity()`
//so you can rewrite your code into something like
sum(1, 4, LongUnaryOperator.identity())
You can also rewrite your code using streams like
public static long sum(long min, long max, LongUnaryOperator mapper) {
return LongStream.rangeClosed(min, max).map(mapper).sum();
}
Related
Suppose I am given integers a and b such that a range of interest is formed, of integers in [a,b]. The range can span well over 10^9 integers. I want to sum the values of a given function f : N -> N over all integers a <= n <= b. The range is very large so I want to do this using multithreading.
Less formaly, I want to parallelize the following code:
long sum = 0;
for (long n = a ; n <= b ; n++)
sum += f(n);
System.out.println(sum);
Ideally (at least in my mind), the range will divided equally across the available number of threads available by the processor (suppose f(n) has near-identical complexity and running time for each n in range). The values are completely independent, and f could really be any function. For example, it could output the sum of digits of the number, but it really could be anything, it's just an example.
Is there a general way to do exactly that in Java using multithreading?
This particular use-case fits very well for a parallel stream. See tutorial by Oracle. Use java.util.stream.LongStream class for a stream of 64-bit long integers.
You can implement it like this:
long sum = LongStream.rangeClosed(a, b)
.parallel()
.map(n -> f(n))
.sum();
System.out.println(sum);
You probably want to look into the fork/join framework; it's a generalized approach to this principle of splitting up a task into a great many little independent tasks and then combining them back together, and gives you all control you'd want about how to spin off threads.
Alternatively, you can use the parallel() method of the stream API, but note that this method doesn't explain or guarantee much about how it works. You have no control over which aspect is parallelized, and no control over the amount of threads that'll be involved. For trivial cases you might as well use it, but as a rule, if 'uhoh I better write this in parallel or it would be too slow' is relevant, then you need some guarantees and some control. Here's oracle's tutorial/explanation on parallel streams. For this specific case it does seem like it would more or less do what you want (it gets tricky if e.g. the stream you attempt to apply this to is e.g. what Files.lines gives you - where the parallelism gets potentially stymied by where it is applied vs. where the bottleneck is).
RecursiveTask is suitable for such a problem. Threads will be managed by the ForkJoinPool.
The general idea is to decompose the problem into shorter sub-problems, up to the point a single thread is able to manage the given sub-problem by itself.
class RecursiveSum extends RecursiveTask<Long> {
private final int THLD = 1_000;
private int low, high;
public RecursiveSum(int high) {
this(0,high);
}
public RecursiveSum(int low, int high) {
this.low = low; this.high = high;
}
private long sum(int l,int h) {
long sum = 0;
for (int i=l; i<h; i++) sum += i;
return sum;
}
#Override
protected Long compute() {
int len = high-low;
if (len<=THLD) return sum(low,high);
RecursiveSum rhalf = new RecursiveSum(low+len/2,high);
rhalf.fork();
RecursiveSum lhalf = new RecursiveSum(low,low+len/2);
high = low+len/2;
return lhalf.compute()+rhalf.join();
}
}
and use it like this:
long r = new RecursiveSum(1_000_000_000).invoke();
System.out.println("Sum="+r);
create your sum class (edit 'f' function to your function):
class sumFun implements Callable<Long> {
public long f(long num){
return num;
}
private long a;
private long b;
public sumFun(long a, long b) {
this.a = a;
this.b = b;
}
#Override
public Long call() {
long sum = 0;
for (long i = a; i <= b; i++) {
sum += f(i);
}
return sum;
}
}
in main :
public static void main(String[] args) throws InterruptedException, ExecutionException {
long start = 1;
long end = 10000000;
int numOfThreads = 5;
long step = (end - start + 1) / numOfThreads;
List<sumFun> tasks = new ArrayList<>();
for (long i = start; i <= end; i += step) {
long tmp = end;
if(i+step-1 < end){
tmp = i+step-1;
}
tasks.add(new sumFun(i, tmp));
}
ExecutorService executor = Executors.newFixedThreadPool(numOfThreads);
List<Future<Long>> results = executor.invokeAll(tasks);
long sum = 0;
for (Future<Long> result : results) {
sum += result.get();
}
System.out.println("sum = " + sum);
executor.shutdown();
}
I was trying figure out why the below solution failed for a single performance test case for the 'Max Double Slice Sum' problem in the codility website: https://codility.com/demo/take-sample-test/max_double_slice_sum
There is another solution O(n) space complexity which is easier to comprehend overhere: Max double slice sum. But i am just wondering why this O(1) solution doesn't work. Below is the actual code:
import java.util.*;
class Solution {
public int solution(int[] A) {
long maxDS = 0;
long maxDSE = 0;
long maxS = A[1];
for(int i=2; i<A.length-1; ++i){
//end at i-index
maxDSE = Math.max(maxDSE+A[i], maxS);
maxDS = Math.max(maxDS, maxDSE);
maxS = Math.max(A[i], maxS + A[i]);
}
return (int)maxDS;
}
}
The idea is simple as follow:
The problem can be readdress as finding max(A[i]+A[i+1]+...+A[j]-A[m]); 1<=i<=m<=j<=n-2; while n = A.length; we call A[m] is missing element within the slice.
maxS[i] will keep max slice which end at current index i; in other words, = max(A[t] + ... + A[i]); while t < i; so when i=1; maxS = A[1]; Note that in solution, we don't keep array but rather latest maxS at current index (See above code).
maxDSE[i] is max of all double slice which end at i; in other words, = max(A[t]+A[t+1]+...+A[i]-A[m])--end at A[i]; maxDS is the final max of double slice sum which we try to find.
Now, we just use a for-loop from i=2; -> i=A.length-2; For each index i, we notice some findings:
If the missing element is A[i], then maxDSE[i] = maxS[i-1] (max sum of
all slice which end at i-1 => or A[t] + ... + A[i] - A[i]);
If missing element is not A[i] -> so it must be somewhere from A[1]->A[i-1] -> maxDSE = maxDSE[i-1] + A[i]; such as A[t] + ... + A[i] - A[m] (not that A[i] must be last element) with t
so maxDSE[i] = Math.max(maxDSE[i-1]+A[i], maxS[i-1]);
maxDS = Math.max(maxDS, maxDSE); max amount all maxDSE;
and maxS[i] = Math.max(A[i], maxS[i-1]+A[i]);
by that way, maxDS will be the final result.
But strange that, I was only able to get 92%; with one failed performance test case as shown here:
medium_range
-1000, ..., 1000
WRONG ANSWER
got 499499 expected 499500
Could anyone please enlighten me where is problem in my solution? Thanks!
Ok, I found the error with my code. Seems that I forgot one corner cases. When calculate DSE[i], in cases A[i] is missing number, maxS should contain the case when array is empty. In other word, maxS should be calculated as:
maxS[i] = Math.max(0, Math.max(A[i]+maxS[i-1], A[i])); while 0 is for case of empty subarray (end at i-th); Math.max(A[i]+maxS[i-1], A[i]) is max of all slice with at least one element (end at i-index). The complete code as follow:
import java.util.*;
class Solution {
public int solution(int[] A) {
long maxDS = 0;
long maxDSE = 0;
long maxS = A[1];
for(int i=2; i<A.length-1; ++i){
maxDSE = Math.max(maxDSE+A[i], maxS);
maxDS = Math.max(maxDS, maxDSE);
maxS = Math.max(0, Math.max(A[i], maxS + A[i]));
}
return (int)maxDS;
}
}
It seems that for the input [-11, -53, -4, 38, 76, 80], your solution doesn't work. Yes, it tricks all the codility test cases, but I managed to trick all codility test cases for other problems too.
If you don't just want to trick codility, but also you want to come with a good solution, I suggest that you create a loop and a large number of random test cases (in number of elements and element values), and create a test method of your own, that you are sure works (even if the complexity is quadratic), compare the results from both methods and then analyze the current random input that doesn't fit.
Here is clear solution. Best approach is to use algorithm of Kanade O(N) and O(1) by space
public class DuplicateDetermineAlgorithm {
public static boolean isContainsDuplicate(int[] array) {
if (array == null) {
throw new IllegalArgumentException("Input array can not be null");
}
if (array.length < 2) {
return false;
}
for (int i = 0; i < array.length; i++) {
int pointer = convertToPositive(array[i]) - 1;
if (array[pointer] > 0) {
array[pointer] = changeSign(array[pointer]);
} else {
return true;
}
}
return false;
}
private static int convertToPositive(int value) {
return value < 0 ? changeSign(value) : value;
}
private static int changeSign(int value) {
return -1 * value;
}
}
I have coded it in vb.net and got 100/100 getting idea form solution by Guillermo
Private Function solution(A As Integer()) As Integer
' write your code in VB.NET 4.0
Dim Slice1() As Integer = Ending(A)
Dim slice2() As Integer = Starting(A)
Dim maxSUM As Integer = 0
For i As Integer = 1 To A.Length - 2
maxSUM = Math.Max(maxSUM, Slice1(i - 1) + slice2(i + 1))
Next
Return maxSUM
End Function
Public Shared Function Ending(input() As Integer) As Integer()
Dim result As Integer() = New Integer(input.Length - 1) {}
result(0) = InlineAssignHelper(result(input.Length - 1), 0)
For i As Integer = 1 To input.Length - 2
result(i) = Math.Max(0, result(i - 1) + input(i))
Next
Return result
End Function
Public Shared Function Starting(input() As Integer) As Integer()
Dim result As Integer() = New Integer(input.Length - 1) {}
result(0) = InlineAssignHelper(result(input.Length - 1), 0)
For i As Integer = input.Length - 2 To 1 Step -1
result(i) = Math.Max(0, result(i + 1) + input(i))
Next
Return result
End Function
Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, value As T) As T
target = value
Return value
End Function
Visit Codility to see the results
The task is the following:
A zero-indexed array A consisting of N different integers is given. The array contains integers in the range [1..(N + 1)], which means that exactly one element is missing.
Your goal is to find that missing element.
Write a function:
class Solution { public int solution(int[] A); }
that, given a zero-indexed array A, returns the value of the missing element.
For example, given array A such that:
A[0] = 2
A[1] = 3
A[2] = 1
A[3] = 5
the function should return 4, as it is the missing element.
Assume that:
N is an integer within the range [0..100,000];
the elements of A are all distinct;
each element of array A is an integer within the range [1..(N + 1)].
Complexity:
expected worst-case time complexity is O(N);
expected worst-case space complexity is O(1), beyond input storage (not counting the storage required for input arguments).
Elements of input arrays can be modified.
Now, my solution is the following:
// you can also use imports, for example:
// import java.util.*;
// you can use System.out.println for debugging purposes, e.g.
// System.out.println("this is a debug message");
class Solution {
public int solution(int[] A) {
long nPlusOneSum = (A.length + 2) * (A.length + 1) / 2;
long arraySum = 0;
for (int element : A)
arraySum += element;
return (int)(nPlusOneSum - arraySum);
}
}
the problem is that i have the following results:
I don't quite understand why I'm having those results in large_range and large2 tests.
I made a sort of a test myself which should simulate large array:
import org.junit.Before;
import org.junit.Test;
public class SomeOtherTest {
int[] maxArray;
int N = 100000;
#Before
public void setUp() {
maxArray = new int[N];
for (int i = 0; i < maxArray.length; i ++) {
maxArray[i] = i + 1;
}
maxArray[0] = maxArray.length + 1;
}
#Test
public void test() {
System.out.println(solution(maxArray));
}
public int solution(int[] A) {
long nPlusOneSum = (A.length + 2) * (A.length + 1) / 2;
long arraySum = 0;
for (int element : A)
arraySum += element;
return (int)(nPlusOneSum - arraySum);
}
}
but it provides me the correct answer which is 1 (used jdk 1.8 something as in codility)
A link to the test results: https://codility.com/demo/results/demoWAS9FA-5FA/
EDIT:
this solution:
class Solution {
public int solution(int[] A) {
long nPlusOneSum = (A.length + 2) * (A.length + 1) / 2;
for (int element : A)
nPlusOneSum -= element;
return (int)nPlusOneSum;
}
}
gives the same result: https://codility.com/demo/results/demoWAS9FA-5FA/
EDIT2
as soon as I introduced temporary variable to hold array length, test passed
code:
class Solution {
public int solution(int[] A) {
long numberOfElementsPlusOne = A.length + 1;
long nPlusOneSum = numberOfElementsPlusOne * (numberOfElementsPlusOne + 1) / 2;
for (int element : A)
nPlusOneSum -= element;
return (int)nPlusOneSum;
}
}
result: https://codility.com/demo/results/demoE82PUM-JCA/
EDIT3
the weird thing is that test still produces correct results, even despite that during it evaluation, overflow occurs.
nPlusOneSum gets overflowed and gets value 705182705 instead of 5000150001.
arraySum doesn't get overflowed and gets value of 5000150000
Then at return statement nPlusOneSum - arraySum is evaluated to -4294967295 which for some reason is then by conversion to (int) gets the correct value 1.
What happens exactly when operation overflows it's type in java?
The trick is that A.length is integer. You should convert it to long before using.
public int solution(int[] A) {
long sum = 0;
for (int element: A) {
sum += element;
}
long expectedSum = (((long) A.length + 1) * ((long) A.length + 2)) / 2;
return (int) (expectedSum - sum);
}
According to java lang spec:
http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.17
The type of a multiplicative expression is the promoted type of its
operands
So resulting type of multiplication of two int is also an int which silently overflows for values around 100.000, the solution would be to change type of operands to long.
EDIT
the weird thing is that test still produces correct results, even despite that during it evaluation, overflow occurs.
There is small catch over here and Its:
Suppose length of your arrays is 100,000. You are trying to find the sum using the formula (N * (N+1))/2, that mean (100,000 * 100,101)/2. So here it multiplies both the numbers first which already exceeded the Max data type value. Hence you have seen the error.
public int solution(int[] arr) {
int realLen = arr.length + 1;
long realSum = 0;
if(realLen%2 == 0) {
realSum = (realLen/2) * (realLen + 1);
} else {
realSum = realLen * ((realLen + 1)/2);
}
for(int i = 0; i < arr.length; i++) {
realSum = realSum - arr[i];
}
return (int)realSum;
}
So I need to develop a method to find the smallest digit in an integer.
Here is my implementation
public int find(int n){
if(n < 10) return n;
return Math.min(n%10, find(n/10));
}
You can change the int by long ...
If you're interested in learning how to figure this out yourself (and you should be), I would try following these steps.
Do the process in your head, slowly - or even better, write the steps on paper! Take notice of each step you take.
Step one may be: look at the first digit
Consider the steps you've created. Are there parts which seem to be repeating themselves? These parts will likely be your recursive function.
Rewrite the steps as a recursive function (in plain English)
Translate the steps into your programming language; Java, in this case.
If you want, you can even leave the plain english steps in your code behind each line as comments, so everyone can easily follow your code
Personally I think a for loop would be quicker and easier than a recursive function. But for recursion or a for loop you need something to iterate on. Easiest way is to convert the number to a string and then iterate through it doing needed comparisons.
In your main:
int i = 578329;
String s = Integer.toString(i);
s = FindSmallest(s);
Call the function:
private String FindSmallest(String s){
if(s.length() <= 1)
return s;
String sFirstChar = s.substring(0,1);
String sSecondChar = s.substring(1,2);
int iFirst = Integer.parseInt(sFirstChar);
int iSecond = Integer.parseInt(sSecondChar);
if(iFirst < iSecond)
return FindSmallest( sFirstChar + s.substring(2));
else
return FindSmallest(sSecondChar + s.substring(2));
}
public static int find(int num) {
if(num < 10){
return num;
}
int d = num % 10;
int pmin = find(num / 10);
return (d <= pmin) ? d : pmin;
}
You can also write:
public static int minDigit(int n, int min){
if(n!=0) {
if(n%10 < min) {
min = n%10;
}
return minDigit(n/10, min);
}
return min;
}
Does Java have an equivalent to Python's range(int, int) method?
Old question, new answer (for Java 8)
IntStream.range(0, 10).forEach(n -> System.out.println(n));
or with method references:
IntStream.range(0, 10).forEach(System.out::println);
Guava also provides something similar to Python's range:
Range.closed(1, 5).asSet(DiscreteDomains.integers());
You can also implement a fairly simple iterator to do the same sort of thing using Guava's AbstractIterator:
return new AbstractIterator<Integer>() {
int next = getStart();
#Override protected Integer computeNext() {
if (isBeyondEnd(next)) {
return endOfData();
}
Integer result = next;
next = next + getStep();
return result;
}
};
I'm working on a little Java utils library called Jools, and it contains a class Range which provides the functionality you need (there's a downloadable JAR).
Constructors are either Range(int stop), Range(int start, int stop), or Range(int start, int stop, int step) (similiar to a for loop) and you can either iterate through it, which used lazy evaluation, or you can use its toList() method to explicitly get the range list.
for (int i : new Range(10)) {...} // i = 0,1,2,3,4,5,6,7,8,9
for (int i : new Range(4,10)) {...} // i = 4,5,6,7,8,9
for (int i : new Range(0,10,2)) {...} // i = 0,2,4,6,8
Range range = new Range(0,10,2);
range.toList(); // [0,2,4,6,8]
Since Guava 15.0, Range.asSet() has been deprecated and is scheduled to be removed in version 16. Use the following instead:
ContiguousSet.create(Range.closed(1, 5), DiscreteDomain.integers());
You can use the following code snippet in order to get a range set of integers:
Set<Integer> iset = IntStream.rangeClosed(1, 5).boxed().collect
(Collectors.toSet());
public int[] range(int start, int stop)
{
int[] result = new int[stop-start];
for(int i=0;i<stop-start;i++)
result[i] = start+i;
return result;
}
Forgive any syntax or style errors; I normally program in C#.
public int[] range(int start, int length) {
int[] range = new int[length - start + 1];
for (int i = start; i <= length; i++) {
range[i - start] = i;
}
return range;
}
(Long answer just to say "No")
Java 9 - IntStream::iterate
Since Java 9 you can use IntStream::iterate and you can even customize the step. For example if you want int array :
public static int[] getInRange(final int min, final int max, final int step) {
return IntStream.iterate(min, i -> i < max, i -> i + step)
.toArray();
}
or List :
public static List<Integer> getInRange(final int min, final int max, final int step) {
return IntStream.iterate(min, i -> i < max, i -> i + step)
.boxed()
.collect(Collectors.toList());
}
And then use it :
int[] range = getInRange(0, 10, 1);
IntStream.range(0, 10).boxed().collect(Collectors.toUnmodifiableList());
Groovy's nifty Range class can be used from Java, though it's certainly not as groovy.
The "Functional Java" library allows to program in such a way to a limited degree, it has a range() method creating an fj.data.Array instance.
See:
http://functionaljava.googlecode.com/svn/artifacts/3.0/javadoc/fj/data/Array.html#range%28int,%20int%29
Similarly the "Totally Lazy" library offers a lazy range method:
http://code.google.com/p/totallylazy/
I know this is an old post but if you are looking for a solution that returns an object stream and don't want to or can't use any additional dependencies:
Stream.iterate(start, n -> n + 1).limit(stop);
start - inclusive
stop - exclusive
If you mean to use it like you would in a Python loop, Java loops nicely with the for statement, which renders this structure unnecessary for that purpose.
Java 8
private static int[] range(int start, int stop, int step) {
int[] result = new int[(stop-start)%step == 0 ? (stop-start)/step : (stop-start)/step+1];
int count = 0;
Function<Integer, Boolean> condition = step > 0 ? (x) -> x < stop : (x) -> x > stop;
for (int i = start; condition.apply(i); i += step) {
result[count] = i;
count++;
}
return result;
}