We are about to switch to a new forum software. Until then we have removed the registration on this forum.
Hi there.
According to the java docs I can declare an ArrayList with an initial size: public ArrayList(int initialCapacity)
Yet when I execute this:
ArrayList<PVector> tpv = new ArrayList<PVector>(2);
println("1: init tpv size: ",tpv.size());
tpv.add(new PVector());
tpv.add(new PVector());
println("2: init tpv size: ",tpv.size());
I get the following output:
1: init tpv size: 0
2: init tpv size: 2
This is a simplified case of my ultimate goal which is trying to initialize tpv with the size of another PVector array:
ArrayList<PVector> tpv = new ArrayList<PVector>(pva.size());
Am I doing something wrong? Am I misunderstanding the javadoc? Can I declare tpv with an initial size?
Answers
Ok. Wrapping my head around that. (It's been a long time since I've dealt with a strictly typed language.)
So I declared a capacity and nothing more. It's just an empty container of a given size with nothing in it. Which is why I get an IndexOutOfBoundsException when I attempt to
put
an element in the array at index 0, even though I've initialized it with a size of 2: the slot at zero itself hasn't been initialized to contain an element yet. Is that it?Ok, so to extend the question: how do I initialize tpv with PVector elements? In a loop of .add() methods? Is there not a way java can automatically assume that I want my array initialized with PVector elements, instead of just creating blank slots that I need to fill by hand?
@Aleksi -- re:
I could be wrong, but I suspect you are not approaching this problem in the right way.
An array (
[]
) is given a fixed size on declaration, and you manage that. However, part of the entire point of anArrayList
is that its capacity is almost always an internal implementation detail -- an ArrayList automatically makes itself bigger as you add things, so you usually don't and shouldn't care what it is doing internally.Just add stuff. It is whatever length it is based on stuff you add. While it is technically possible to reference the capacity, if you are doing so then you are (usually) using it wrong.
Don't bother with capacity. Just add as many things as you want. If you want brevity of initialization, you can do it in a one-line for loop:
...of course, if you don't yet know what goes in your PVectors then you might be adding them at the wrong time. It is kind of like counting out exactly as many empty boxes as you need to move, loading the empty boxes into your moving van, and then putting your stuff into each box that is already in the van. Why would you do that? Just put your stuff in boxes. Every time you fill a box, put the full box in the van.
On the other hand, if you want a collection of n points that each have a default initialization (0,0) -- like you plan to random-walk a cloud of dots from the center of the screen -- then adding a lot of new PVectors with no arguments makes sense.
The point of setting the capacity is to avoid unnecessary resizing of the underlying array. It starts with a capacity of 10 and when you add the 8th element to the list (75% capacity exceeded) it doubles the capacity. It does this by
1) Creating a new array (double the existing size)
2) Copies the elements from the existing array to the new array
3) Sets the reference of the underlying array to the new array
4) Dispose of the old array (garbage collected)
So it you want to initialise the list to hold 100 elements (and you add them 1 by 1) it will be resized 4 times
10 > 20
20 > 40
40 > 80
80 > 160
To avoid this simply set the capacity to 200 when creating the list.
Thank you both for your answers.
My purpose in initializing the capacity of the array was to repeatedly loop through the known number of elements of other arrays to store and process ever-changing results. I know, going into the loop, that the size of the source arrays will never change.
Coming from untyped languages that don't need to first "add" elements that are then emended is just one more "gotcha" that I'm hitting as I get my legs working in java.
Hi quark, thank you for the (cross-posted) explanation.
If you have a collection (List, Set, Map) of PVector objects called
c
then you can create a new ArrayList with these PVectors then useArrayList<PVector> tpv = new ArrayList<PVector>(c);
If you have an array of PVector objects called
a
then you can create a new ArrayList with these PVectors then useArrayList<PVector> tpv = new ArrayList<PVector>(Arrays.asList(a));
@quark, that 75% threshold is the default value for the HashMap, not the ArrayList! :-\"
AFAIK, even though Java doesn't specify the growth value for it, the underlying array is doubly-resized exactly when we attempt to add() an element when the size() is already equal to the internal capacity. Not completely sure though. It's Java flavor dependent. :P
@quark
Wouldn't tpv just contain pointers to the same memory locations of each element in c? Is there a way to copy each source PVector element to tpv in a declaration? The values in tpv will change; the source ones cannot.
@quark, unless we
import
the Arrays utilityclass
1st, your code line's gonna fail! #-oAlternatively, use its whole
package
name: *-:)ArrayList<PVector> vecs = new ArrayList<PVector>(java.util.Arrays.asList(a));
@Aleksi, I don't think the add() got anything to do w/ typed or untyped languages.
If by untyped you've meant JS, it's just its array implementation is much more flexible (and slower) than Java's.
The only Java container which comes a little closer to JS' array is the LinkedList:
http://Docs.Oracle.com/javase/8/docs/api/java/util/LinkedList.html
What do you mean by c. I don't see anything called c in your posted example. :-/
@GoToLoop
What I meant was that in java I can't simply say something like
v = [PVector([1,2,3])]
like I've grown accustomed to. No, in java I need to jump through some ugly hoops first:
ArrayList<PVector>v = new ArrayList<PVector>(); v.add(new PVector()); // initialize first v.set(0, new PVector(1,2,3)); // reset later
No matter how I look at that, it seems kind of crazy to me. 8-}
But every language has its own quirks and nomenclature, and as I learn java I come to understand how and why it does what it does.
(And if by JS you meant JavaScript, other than a drive-by familiarity, I've never had the (dis)pleasure of using it.)
@GoToLoop: > What do you mean by c. I don't see anything called c in your posted example.
I was referring to @quarks's example;
ArrayList<PVector> tpv = new ArrayList<PVector>(c);
Thank you again for your replies and advice.
So my other guess is Python. Guess what, Processing's IDE (PDE) got Python Mode too! :-$
If you just need a regular Java array, you can do the following: ~O)
BtW, no need to pass a List to PVector like you did in Python. :-\"
The following is pretty enough:
vecs = [ PVector(1, 2, 3) ]
Yes, python indeed. ;) Except if I'm going to learn processing, I'd rather learn it in it's native environment, rather than work with a bastardization of python like jython. (Plus I get to learn another language!)
As for the regular java array, thanks for the info. However, in the method I'm developing I don't know the size of the PVector arrays coming in that tpv needs to copy, hence my initial question.
Are you sure of it? Where those PVector objects come from?
Indeed, if you're not sure of the size, or the size keeps changing later, vanilla arrays are very awkward for such, and you're gonna need another container type, like the aforementioned ArrayList. 8-|
Keep in mind that in Java only actual regular vanilla arrays are allowed to use the brackets
[]
syntax.Any other containers have to rely on methods for the same purpose. ~:>
Yes, I'm sure of it. That's why I'm using the ArrayList. ;)
Oh, the array of PVectors are coming from a csv that I parse. Some fields in a row can have an arbitrary number of vectors. The method I'm developing processes the arrays of PVectors using tpv as a mutable copy of the original arrays. That's why it would be convenient to instantiate tpv as a copy of a source array.
why not
or is there a reason you're adding specifically at 0? java dequeues let you push() and pop() if that's what you want:
https://docs.oracle.com/javase/7/docs/api/java/util/ArrayDeque.html
Hi koogs.
I have a nested loop further in the method. The inner loop does a counter iteration over the source arrays, using tpv to process the source array values without changing them.
Essentially it looks like this:
I don't know what the sourceArray PVector values are until I enter the loop.
The example you've quoted was a short-hand illustration of what I need to do: create a placeholder element before the loop; set the element inside the loop.
I appreciate everyone's insights. Thank you.
I ended up taking the advice of @jeremydouglass with the following code:
It's not what I would call elegant; but, with my currently limited knowledge of java, this seems like a perfectly adequate solution for now -- because things are working.
Can you post a sample of that ".csv" file?
If more folks posted their external files at the beginning, solutions would arrive faster. I-)
I fail to see how posting the .csv file is germaine to the question I posed ;;), but here's the relevant excerpt:
Entries are tab separated (rather than comma). There are over a score of quasi-enums that serve as common vectors. Vectors can be entered as normal vectors (ie:
(x,y,z)
), as quasi-enums (ie:pW;vNW
), or any combination thereof (ie:(pS.x, tHalf.y, -5)
). Multiple vectors in a field are delimited by semi-colons.I have a method that parses the entries, converts them to their proper values, and stores them in the relevant ArrayList.
code is easier to fix if we have working examples, rather than just descriptions of fragments of the problem.
Understood, and I agree. But the contents and parsing of the csv don't have anything to do with the question about initializing a new ArrayList with a copy of another ArrayList's values... does it? I thought rather than muddy the waters with irrelevant information I'd just focus on the question at hand.
@Aleksi -- I believe koogs is recommending, in general, to start with an MCVE on the forums to get the best help.
Thank you, @jeremydouglass. I will remember that in the future.
Then your file is ".tsv" and not ".csv", right? ;;)
You're right on that! But posting enough info early on helps us see what your actual end goal is.
Before posting your file, your questions weren't making much sense. At least for moi. ~:>
That's the main reason I've asked you to post your file. L-)
You kept stating that you couldn't use a vanilla array b/c you apparently was unable to determine the size for the array.
That didn't make sense to me, b/c every time I've dealt w/ ".csv" & ".tsv" files, I was always able to determine the size before creating the array for storing those data!
And even your quasi-enum ".tsv" file hasn't changed that in the least! $-)
In short, you don't need a List, just a vanilla Java array! \m/
In order to demo that, I've coded a sketch which tries to somehow emulate yours.
At least what I could guess. What I didn't, I've just made it up! :ar!
For example, I dunno what PVector a "tCenter", "tHalf" or "tWidth" would represent. :-/
So I've just arbitrarily created a Map container, which maps those quasi-enum strings from your ".tsv" to a specific PVector. :-j
Apart from that Map, notice that everything else is just regular Java arrays. ~O)
Anyways, here's my made-up sketch, attempting to guess how yours works: 3:-O
vectors.tsv:
QuasiPVecParser.pde:
https://DZone.com/articles/performance-evaluation-of-java-arraylist
@GoToLoop... Either you have a great deal of free time, a zealous commitment to helping us out, a delight in solving problems, or some other urge driving you... but whatever it is I thank you for going that extra mile. =D>
Even though my code works, still being new at java it's not what I would call elegant, or even java-esque, so much as clumsy brute force. But I'm just starting to get off my training wheels with java, so I'm ready to move to the next level. Your example is timely and I will study it.
While I followed the same general approach (eg: using a HashMap for my quasi-enums; switch statements for parsing the endpts fields; etc.), your code, working with Java, is far more elegant than my lumbering and bloated code. I also see some things I haven't come across yet, like
@ Override String toString
....I was going to ask what the advantage is of a using a vanilla array over an ArrayList. The link you provided suggests a performance difference, but are there other reasons for using a vanilla array over an ArrayList?
Thank you again for your example.
The reason I've posted the link above was more about the capacity subject you were asking about 1st. :\">
About which 1 is faster, a vanilla array or an ArrayList, for access time, raw arrays beat down any List.
An ArrayList is used in place of vanilla arrays when we need to keep changing its length.
B/c I was able to pre-determine the length of all of my arrays, and they didn't change later on, I didn't pick ArrayList containers, and simply used 100% vanilla arrays in my code above. \m/
When we println() an object in Java, by default it displays garbage. :-&
Unfortunately we need to
@Override
Object::toString() in an object'sclass
in order to have any meaningful info spit out from our objects: :-<