I am reviewing someone else's Grails code and I see the following:
Set<Integer> weeks = new ArrayList<Integer>()
It looks like after this line is set, Grails thinks that weeks is a HashSet. I am not well versed in either Java or Grails, and the (java) documentation looks like ArrayList extends List and HashSet extends Set, but that this direct construction wouldn't work. Is this a Grails thing? Thanks.
It's somewhat unusual in Groovy to see new ArrayList<Integer>() since [] works identically and is way less verbose, so I would have written that as Set<Integer> weeks = []. Then it's a bit more clear what's going on - Groovy is converting one collection type to another, with the [] really as a convenient way to create a holder and populate the initial data (if there is any). Since there's no syntactic sugar for collections other than [] for List and [:] you need these conversions.
def weeks = [] as Set is probably the more common syntax. This is also more clear since [] is just temporary and using "as" does the conversion, and more explicitly than just declaring the type on the left side.
You can also use this to convert collections to arrays. You can't use Java syntax to create arrays since it uses braces and looks like a Closure definition, so instead of int[] numbers = new int[] { 1, 2, 3 } you have to do int[] numbers = [1, 2, 3] or def numbers = [1, 2, 3] as int[].
Related
I would like to know when I can use IntStream.range effectively. I have three reasons why I am not sure how useful IntStream.range is.
(Please think of start and end as integers.)
If I want an array, [start, start+1, ..., end-2, end-1], the code below is much faster.
int[] arr = new int[end - start];
int index = 0;
for(int i = start; i < end; i++)
arr[index++] = i;
This is probably because toArray() in IntStream.range(start, end).toArray() is very slow.
I use MersenneTwister to shuffle arrays. (I downloaded MersenneTwister class online.) I do not think there is a way to shuffle IntStream using MersenneTwister.
I do not think just getting int numbers from start to end-1 is useful. I can use for(int i = start; i < end; i++), which seems easier and not slow.
Could you tell me when I should choose IntStream.range?
There are several uses for IntStream.range.
One is to use the int values themselves:
IntStream.range(start, end).filter(i -> isPrime(i))....
Another is to do something N times:
IntStream.range(0, N).forEach(this::doSomething);
Your case (1) is to create an array filled with a range:
int[] arr = IntStream.range(start, end).toArray();
You say this is "very slow" but, like other respondents, I suspect your benchmark methodology. For small arrays there is indeed more overhead with stream setup, but this should be so small as to be unnoticeable. For large arrays the overhead should be negligible, as filling a large array is dominated by memory bandwidth.
Sometimes you need to fill an existing array. You can do that this way:
int[] arr = new int[end - start];
IntStream.range(0, end - start).forEach(i -> arr[i] = i + start);
There's a utility method Arrays.setAll that can do this even more concisely:
int[] arr = new int[end - start];
Arrays.setAll(arr, i -> i + start);
There is also Arrays.parallelSetAll which can fill an existing array in parallel. Internally, it simply uses an IntStream and calls parallel() on it. This should provide a speedup for large array on a multicore system.
I've found that a fair number of my answers on Stack Overflow involve using IntStream.range. You can search for them using these search criteria in the search box:
user:1441122 IntStream.range
One application of IntStream.range I find particularly useful is to operate on elements of an array, where the array indexes as well as the array's values participate in the computation. There's a whole class of problems like this.
For example, suppose you want to find the locations of increasing runs of numbers within an array. The result is an array of indexes into the first array, where each index points to the start of a run.
To compute this, observe that a run starts at a location where the value is less than the previous value. (A run also starts at location 0). Thus:
int[] arr = { 1, 3, 5, 7, 9, 2, 4, 6, 3, 5, 0 };
int[] runs = IntStream.range(0, arr.length)
.filter(i -> i == 0 || arr[i-1] > arr[i])
.toArray();
System.out.println(Arrays.toString(runs));
[0, 5, 8, 10]
Of course, you could do this with a for-loop, but I find that using IntStream is preferable in many cases. For example, it's easy to store an unknown number of results into an array using toArray(), whereas with a for-loop you have to handle copying and resizing, which distracts from the core logic of the loop.
Finally, it's much easier to run IntStream.range computations in parallel.
Here's an example:
public class Test {
public static void main(String[] args) {
System.out.println(sum(LongStream.of(40,2))); // call A
System.out.println(sum(LongStream.range(1,100_000_000))); //call B
}
public static long sum(LongStream in) {
return in.sum();
}
}
So, let's look at what sum() does: it counts the sum of an arbitrary stream of numbers. We call it in two different ways: once with an explicit list of numbers, and once with a range.
If you only had call A, you might be tempted to put the two numbers into an array and pass it to sum() but that's clearly not an option with call B (you'd run out of memory). Likewise you could just pass the start and end for call B, but then you couldn't support the case of call A.
So to sum it up, ranges are useful here because:
We need to pass them around between methods
The target method doesn't just work on ranges but any stream of numbers
But it only operates on individual numbers of the stream, reading them sequentially. (This is why shuffling with streams is a terrible idea in general.)
There is also the readability argument: code using streams can be much more concise than loops, and thus more readable, but I wanted to show an example where a solution relying on IntStreans is functionally superior too.
I used LongStream to emphasise the point, but the same goes for IntStream
And yes, for simple summing this may look like a bit of an overkill, but consider for example reservoir sampling
IntStream.range returns a range of integers as a stream so you can do stream processing over it.
like taking square of each element
IntStream.range(1, 10).map(i -> i * i);
Here are few differences that comes to my head between IntStream.range and traditional for loops :
IntStream are lazily evaluated, the pipeline is traversed when calling a terminal operation. For loops evaluate at each iteration.
IntStream will provides you some functions that are commonly applied to a range of ints such as sum and avg.
IntStream will allow you to code multiple operation over a range of int in a functional way which read more fluently - specially if you have a lot of operations.
So basically use IntStream when one or more of these differences are useful to you.
But please bear in mind that shuffling a Stream sound quite strange as a Stream is not a data structure and therefore it does not really make sense to shuffle it (in case you were planning on building a special IntSupplier). Shuffle the result instead.
As for the performance, while there may be a few overhead, you will still iterate N times in both case and should not really care more.
Basically, if you want Stream operations, you can use the range() method. For example, to use concurrency or want to use map() or reduce(). Then you are better off with IntStream.
For example:
IntStream.range(1, 5).parallel().forEach(i -> heavyOperation());
Or:
IntStream.range(1, 5).reduce(1, (x, y) -> x * y)
// > 24
You can achieve the second example also with a for-loop, but you need intermediate variables etc.
Also, if you want the first match for example, you can use findFirst() and cousins to stop consuming the rest of the Stream
It totally depends on the use case. However, the syntax and stream API adds lot of easy one liners which can definitely replace the conventional loops.
IntStream is really helpful and syntactic sugar in some cases,
IntStream.range(1, 101).sum();
IntStream.range(1, 101).average();
IntStream.range(1, 101).filter(i -> i % 2 == 0).count();
//... and so on
Whatever you can do with IntStream you can do with conventional loops. As one liner is more precise to understand and maintain.
Still for negative loops we can not use IntStream#range, it only works in positive increment. So following is not possible,
for(int i = 100; i > 1; i--) {
// Negative loop
}
Case 1 : Yes conventional loop is much faster in this case as toArray has a bit overhead.
Case 2 : I don't know anything about it, my apologies.
Case 3 : IntStream is not slow at all, IntStream.range and conventional loop are almost same in terms of performance.
See :
Java 8 nested loops with streams & performance
You could implement your Mersenne Twister as an Iterator and stream from that.
Simple question, but everytime I google it there are only examples using an ArrayList, and list.indexOf(3), doesn't work on int[] nums = new int[10]. Soo im a little confused.
Here's the real problem. You appear to think that
int[] nums = new int[10]
is defining a List or a list. It isn't. It is an array. The words "list" and "array" are NOT synonymous in the context of Java. So when you Google for "finding an index of an element in a list" ... you don't get any useful hits.
If you use the >>correct<< terms when searching (Google, SO search, anything) you are far more likely to get useful search results.
For example:
How to find index of int array in Java from a given value?
FWIW, if you want a (real) list of integers in Java you declare it like this:
List<Integer> nums = new ArrayList<>();
Notes
You have to use Integer as the type parameter, not int.
You don't need to provide 10 as a parameter. And if you do, it is a hint that tells the ArrayList what the initial capacity of the list should be. (For an array it is the actual size ... and it can't be changed).
If you want to use indexOf(3) on an array you could create a List from it
ArrayList<Integer> myInts = new ArrayList<Integer>(Arrays.asList(array))
and then you can use
myInts.indexOf(3)
Given that:
int[] a = {1, 2, 3, 4};
int[] b = {1, 2, 3, 4, 5};
How to asser that "a" is a subset of "b" using hamcrest matchers?
The following works
assertThat(Arrays.asList(b), hasItems(a));
But since I am creating "a" from "b", I would prefer to apply the asserts on "a" as the value.
Something like
assertThat(a, isSubsetOf(b));
Additionally it is preferable to avoid converting the array to a list.
You can use a combination of the Every and IsIn matcher:
assertThat(Arrays.asList(a), everyItem(in(b)));
This does check if every item of a is contained in b. Make sure a and b are of type Integer[] otherwise you might get unexpected results.
If you are using an older version of hamcrest (for example 1.3) you can use the following:
assertThat(Arrays.asList(a), everyItem(isIn(b)));
In the latest version isIn is deprecated in favor of in.
Create your own custom matcher by extending org.hamcrest.TypeSafeMatcher and use it in the assertThat() method. You can refer the code of org.hamcrest.collection.IsArrayContaining and create your own matcher
If assertj is an option for you:
assertThat(b).contains(a); // order doesn't matter
assertThat(b).containsSequence(a); // order matters
I am a fairly newbie programmer with a question on arrays in Java. Consider a 2D array, [i][j]. The value of i is determined at run time. The value of j is known to be 7. At [i][6] and [i][7] I want to be able to store a deeper array or list of values. Is it possible to have something like an array within an array, where there is an x and y axis and a z axis at the point of [i][6] and i[7] or will I need a full 3D cube of memory to be able to store and navigate my data?
The Details: My goal is to run a query which takes certain information from two tables (target and attacker) My query is fine and I can get a resultset. What I really want to be able to do is to store the data from my resultset and present it in a table in a more useful format while also using it in a data visualization program. The fields I get are: server_id, target_ip, threat_level, client_id, attacker_ip and num_of_attacks. I could get 20 records that have the same server_id, target_ip, threat_level, client_id but different attacker_ip and num_of_attacks because that machine got attacked 20 times. A third dimension would allow me to do this but the 3rd axis/array would be empty for server_id, target_ip, threat_level, client_id
UPDATE after reviewing the answers and doing some more thinking I'm wondering if using an arraylist of objects would be best for me, and/or possible. Keeping data organized and easily accessible is a big concern for me. In psedu code it would be something like this:
Object[] servers
String server_id
String target
String threat_level
String client_id
String arr[][] // this array will hold attacker_ip in one axis and num_of_attacks in the other in order to keep the relation between the attacking ip and the number of attacks they make against one specific server
In first place, if you have an array DataType[i][j] and j is known to be 7, the 2 greatest indexes you can use are 5 and 6, not 6 and 7. This is because Java array indexes are 0-based. When creating the array you indicate the number of elements, not the maximum index (which always is one less than number of elements).
In second place, there is nothing wrong with using multidimensional arrays when the problem domain already uses them. I can think of scientific applications, data analysis applications, but not many more. If, on the contrary, you are modelling a business problem whose domain does not use multidimensional arrays, you are probably better off using more abstract data structures instead of forcing arrays into the design just because they seem very efficient, experience in other languages where arrays are more important, or other reasons.
Without having much information, I'd say your "first dimension" could be better represented by a List type (say ArrayList). Why? Because you say its size is determined at runtime (and I assume this comes indirectly, not as a magic number that you obtain from somewhere). Lists are similar to arrays but have the particularity that they "know" how to grow. Your program can easily append new elements as it reads them from a source or otherwise discovers/creates them. It can also easily insert them at the beginning or in the middle, but this is rare.
So, your first dimension would be: ArrayList<something>, where something is the type of your second dimension.
Regarding this second dimension, you say that it has a size of 7, but that the first 5 items accept single values while the last 2 multiple ones. This is already telling me that the 7 items are not homogeneous, and thus an array is ill-indicated. This dimension would be much better represented by a class. To understand this class's structure, let's say that the 5 single-valued elements are homogenous (of type, say, BigDecimal). One of the most natural representations for this is array, as the size is known. The 2 remaining, multi-valued elements also seem to constitute an array. However, given that each of its 2 elements contains an unidentified number of data items, the element type of this array should not be BigDecimal as in the previous case, but ArrayList. The type of the elements of these ArrayLists is whatever the type of the multiple values is (say BigDecimal too).
The final result is:
class SecondD {
BigDecimal[] singleValued= new BigDecimal[5] ;
ArrayList<BigDecimal>[] multiValued= new ArrayList<BigDecimal>[2] ;
{
multiValued[0]= new ArrayList<BigDecimal>() ;
multiValued[1]= new ArrayList<BigDecimal>() ;
}
}
ArrayList<SecondD> data= new ArrayList<SecondD>() ;
In this code snippet I'm not only declaring the structures, but also creating them so they are ready to use. Pure declaration would be:
class SecondD {
BigDecimal[] singleValued;
ArrayList<BigDecimal>[] multiValued;
}
ArrayList<SecondD> data= new ArrayList<SecondD>() ;
Array size is not important in Java from a type (and thus structural) point of view. That's why you don't see any 5 or 2.
Access to the data structure would be like
data.get(130).singleValued[2]
data.get(130).multiValued[1].get(27)
A possible variant that could be much clearer in certain cases is
class SecondD {
BigDecimal monday;
BigDecimal tuesday;
BigDecimal wednesday;
BigDecimal thursday;
BigDecimal friday;
ArrayList<BigDecimal> saturday= new ArrayList<BigDecimal>() ;
ArrayList<BigDecimal> sunday= new ArrayList<BigDecimal>() ;
}
ArrayList<SecondD> data= new ArrayList<SecondD>() ;
In this case we are "expanding" each array into individual items, each with a name. Typical access operations would be:
data.get(130).wednesday
data.get(130).sunday.get(27)
Which variant to choose? Well, that depends on how similar or different the operations with the different itemes are. If every time you will perform and operation with monday you will also perform it with tuesday, wednesday, thursday, and friday (not saturday and sunday because these are a completely different kind of thing, remember?), then an array could be better. For example, to sum the items when stores as an array it's only necessary:
element= data.get(130) ;
int sum= 0 ;
for(int e: element.singleValued ) sum+= e ;
While if expanded:
element= data.get(130) ;
int sum= 0 ;
sum+= element.monday ;
sum+= element.tuesday ;
sum+= element.wednesday ;
sum+= element.thursday ;
sum+= element.friday ;
In this case, with only 5 elements, the difference is not much. The first way makes things slightly shorter, while the second makes them clearer. Personally, I vote for clarity. Now, if instead of 5 items they would have been 1,000 or even as few as 20, the repetition in the second case would have too much and the first case preferred. I have another general rule for this too: if I can name every element separately, then it's probably better to do exactly so. If while trying to name the elements I find myself using numbers or sequential letters of the alphabet (either naturally, as in the days of the month, or because things just don't seem to have different names), then it's arrays. You could still find cases that are not clear even after applying these two criteria. In this case toss a coin, start developing the program, and think a bit how things would be the other way. You can change your mind any time.
If your application is indeed a scientific one, please forgive me for such a long (and useless) explanation. My answer could help others looking for something similar, though.
Use ArrayList instead of array primitives. You can have your three dimensions, without the associated inefficient wastage of allocating a "cube"
If not creating a custom class like #nIcE cOw suggested Collections are more cumbersome for this kind of thing than primitive arrays. This is because Java likes to be verbose and doesn't do certain things for you like operator overloading (like C++ does) or give you the ability to easily instantiate ArrayList from arrays.
To exemplify, heres #sbat's example with ArrayLists;
public static <T> ArrayList<T> toAL(T ... input) {
ArrayList<T> output = new ArrayList<T>();
for (T item : input) {
output.add(item);
}
return output;
}
public static void main(String[] args) {
ArrayList<ArrayList<ArrayList<Integer>>> a = toAL(
toAL(
toAL(0, 1, 2)
),
toAL(
toAL(4, 5)
),
toAL(
toAL(6)
)
);
System.out.println(a.get(0).get(0).get(2));
System.out.println(a.get(1).get(0).get(1));
System.out.println(a.get(2).get(0).get(0));
}
Of course, there's nothing syntactically wrong with doing:
int[][][] a = {{{0, 1, 2}}, {{4, 5}}, {{6}}};
System.out.println(a[0][0].length); // 3
System.out.println(a[1][0].length); // 2
System.out.println(a[2][0].length); // 1
In fact, that's what multidimensional arrays in Java are, they're arrays within arrays.
The only problem I see with this is that it might become confusing or difficult to maintain later on, but so would using ArrayLists within ArrayLists:
List<List<List<Integer>>> list = ...;
System.out.println(list.get(0).get(1).get(50)); // using ArrayList
However, there are still reasons as to why you might prefer an array over a collection. But ArrayLists or other collections may be preferable depending on the circumstance.
I am doing some Junit testing on my code, which is meant to produce an arraylist of n prime numbers. I want to compare the created list to a list of known prime numbers in an array, and to do this I need to insert multiple values into an array in my testing class.
So what I have at the moment is
int knownPrimes[] = new int[50];
I know that I could insert values into this array by typing
knownPrimes[1] = 2;
knownPrimes[2] = 3;
etc etc.
I was just wondering how I would do this all in one big chunk, maybe something like:
knownPrimes[] = {2,3,5,7,9...};
but I am not sure of the syntax and I can't find anything on google. Would anyone be able to help me out please ?
Thanks a lot.
int[] knownPrimes = new int[] {2, 3, 5, 7, 9};
As Peter mentioned, the new int[] can be omitted.
try
int[] knownPrimes = {2,3,5,7,9};
or
int[] knownPrimes;
knownPrimes = new int[] {2,3,5,7,9}
I agree with the solutions posted.
A good book is Thinking in Java, by Bruce Eckel. He covers initialization in Chapter 4, "Initialization and Cleanup," and uses Peter's method. You may buy the latest edition or download an older edition for free.
If the list of knownPrimes is not going to be subclassed, you might want to add the keyword final. If it is class variable and you do not want the value to change after the initialization, you might want to add the keyword static. (I suspect that the list of known primes will be the same throughout the execution of the program.) If you want to access the length of the array, use knownPrimes.length.
Oh, and by the way, 9 should not be in the list of knownPrimes.