I am reading data from a file of students where each line is a student, I am then turning that data into a student object and I want to return an array of student objects. I am currently doing this by storing each student object in an arraylist then returning it as a standard Student[]. Is it better to use an arraylist to have a dynamic size array then turn it into a standard array for the return or should I first count the number of lines in the file, make a Student[] of that size then just populate that array. Or is there a better way entirely to do this.
Here is the code if it helps:
public Student[] readStudents() {
String[] lineData;
ArrayList<Student> students = new ArrayList<>();
while (scanner.hasNextLine()) {
lineData = scanner.nextLine().split(" ");
students.add(new Student(lineData));
}
return students.toArray(new Student[students.size()]);
}
Which is better depends on what you need and your data set size. Needs could be - simplest code, fastest load, least memory usage, fast iteration over resultind data set... Options could be
For one-off script or small data sets (tens of thousands of elements) probably anything would do.
Maybe do not store elements at all, and process them as you read them? - least memory used, good for very large data sets.
Use pre-allocated array - if you know data set size in advance - guaranteed least memory allocations - but counting elements itself might be expensive.
If unsure - use ArrayList to collect elements. It would work most efficiently if you can estimate upper bound of your data set size in advance, say you know that normally there is not more than 5000 elements. In that case create ArrayList with 5000 elements. It will resize itself if backing array is full.
LinkedList - probably the most conservative - it allocates space as you go but required memory per element is larger and iteration is slower than for arrays or ArrayLists.
Your own data structure optimized for your needs. Usually the effort is not worth it, so use this option only when you already know the problem you want to solve.
Note on ArrayList: it starts with pre-allocating an array with set of slots which are filled afterwards without memory re allocation. As long as backing array is full a new larger one is allocated and all elements are moved into it. New array size is by default twice the size of previous - normally this is not a problem but can cause out of memory if new one cannot get enough contiguous memory block.
Use an array for a fixed size array. For students that is not the case, so an ArrayList is more suited, as you saw on reading. A conversion from ArrayList to array is superfluous.
Then, use the most general type, here the List interface. The implementation, ArrayList or LinkedList then is a technical implementation question. You might later change an other implementation with an other runtime behavior.
But your code can handle all kinds of Lists which is really a powerful generalisation.
Here an incomplete list of useful interfaces with some implementations
List - ArrayList (fast, a tiny bit memory overhead), LinkedList
Set - HashSet (fast), TreeSet (is a SortedSet)
Map - HashMap (fast), TreeMap (is a SortedMap), LinkedHashMap (order of inserts)
So:
public List<Student> readStudents() {
List<Student> students = new ArrayList<>();
while (scanner.hasNextLine()) {
String[] lineData = scanner.nextLine().split(" ");
students.add(new Student(lineData));
}
return students;
}
In a code review one would comment on the constructor Student(String[] lineData) which risks a future change in data.
Related
I have written Java code to get the list of employee name from database and storing it in a list.
List<String> employeeList = new ArrayList<Integer>();
employeeList = getAllEmployee();
My database changes regularly and number of employees increases or decreases daily.
Normally logic what can I use is getcount from DB and create Arraylist from that count.
I have a thought. Now if I have 3 employee from DB, If I create Arraylist I will create initial capacity of 10. Is there any way to remove the unused space 7 from ArrayList. Also please enlighten me on initial capacity algorithm and load factor too.
Yes, there is a way to remove the unused space. You can use the method trimToSize(), which, according to its Javadoc,
trims the capacity of this ArrayList instance to be the list's current size.
Note that this requires downcasting a List to an ArrayList, by the way.
The current implementation of ArrayList in Oracle's Java 8 runtime has a private method grow(). You can see the implementation if you have a JDK installed, I suppose. It doesn't work with a 'load factor' but uses a different algorithm for determining the new capacity of the underlying array:
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
Plus it does some boundary checking to make sure the ints do not overflow, but that's a different story.
i think this is what you are looking for java.util.ArrayList.trimToSize() method , that trims the capacity of an ArrayList instance to the current size. it will minimize the storage of an ArrayList instance
doclink
You can create a list with a size equals to the desired size.
List<String> list = new ArrayList<String>(desiredSize);
Please note that the code you wrote
List<String> employeeList= new arrayList()<Integer>;
employeeList= getAllEmployee();
probabilly create two lists. One explicitly, the second inside the code of getAllEmployee(). So the best is
List<String> employeeList = getAllEmployee()
and in your getAllEmployee code do something like that
public List<String> getAllEmployee() {
...
int desiredSize = ....
...
List<String> list = new ArrayList<String>(desiredSize);
...
return list;
}
Note that if you are not in an extremely optimized environment (and I think you aren't otherwise you didn't asked for this kind of problem) it is not necessary to save few bytes. If the code is less readable and you have to calculate the desired size with an additional call to the database is not a good programming choice.
I want to know how to add or append a new element to the end of an array. Is any simple way to add the element at the end? I know how to use a StringBuffer but I don't know how to use it to add an element in an array. I prefer it without an ArrayList or list. I wonder if the StringBuffer will work on integers.
You can not add an element to an array, since arrays, in Java, are fixed-length. However, you could build a new array from the existing one using Arrays.copyOf(array, size) :
public static void main(String[] args) {
int[] array = new int[] {1, 2, 3};
System.out.println(Arrays.toString(array));
array = Arrays.copyOf(array, array.length + 1); //create new array from old array and allocate one more element
array[array.length - 1] = 4;
System.out.println(Arrays.toString(array));
}
I would still recommend to drop working with an array and use a List.
Arrays in Java have a fixed length that cannot be changed. So Java provides classes that allow you to maintain lists of variable length.
Generally, there is the List<T> interface, which represents a list of instances of the class T. The easiest and most widely used implementation is the ArrayList. Here is an example:
List<String> words = new ArrayList<String>();
words.add("Hello");
words.add("World");
words.add("!");
List.add() simply appends an element to the list and you can get the size of a list using List.size().
To clarify the terminology right: arrays are fixed length structures (and the length of an existing cannot be altered) the expression add at the end is meaningless (by itself).
What you can do is create a new array one element larger and fill in the new element in the last slot:
public static int[] append(int[] array, int value) {
int[] result = Arrays.copyOf(array, array.length + 1);
result[result.length - 1] = value;
return result;
}
This quickly gets inefficient, as each time append is called a new array is created and the old array contents is copied over.
One way to drastically reduce the overhead is to create a larger array and keep track of up to which index it is actually filled. Adding an element becomes as simple a filling the next index and incrementing the index. If the array fills up completely, a new array is created with more free space.
And guess what ArrayList does: exactly that. So when a dynamically sized array is needed, ArrayList is a good choice. Don't reinvent the wheel.
The OP says, for unknown reasons, "I prefer it without an arraylist or list."
If the type you are referring to is a primitive (you mention integers, but you don't say if you mean int or Integer), then you can use one of the NIO Buffer classes like java.nio.IntBuffer. These act a lot like StringBuffer does - they act as buffers for a list of the primitive type (buffers exist for all the primitives but not for Objects), and you can wrap a buffer around an array and/or extract an array from a buffer.
Note that the javadocs say, "The capacity of a buffer is never negative and never changes." It's still just a wrapper around an array, but one that's nicer to work with. The only way to effectively expand a buffer is to allocate() a larger one and use put() to dump the old buffer into the new one.
If it's not a primitive, you should probably just use List, or come up with a compelling reason why you can't or won't, and maybe somebody will help you work around it.
As many others pointed out if you are trying to add a new element at the end of list then something like, array[array.length-1]=x; should do. But this will replace the existing element.
For something like continuous addition to the array. You can keep track of the index and go on adding elements till you reach end and have the function that does the addition return you the next index, which in turn will tell you how many more elements can fit in the array.
Of course in both the cases the size of array will be predefined. Vector can be your other option since you do not want arraylist, which will allow you all the same features and functions and additionally will take care of incrementing the size.
Coming to the part where you want StringBuffer to array. I believe what you are looking for is the getChars(int srcBegin, int srcEnd,char[] dst,int dstBegin) method. Look into it that might solve your doubts. Again I would like to point out that after managing to get an array out of it, you can still only replace the last existing element(character in this case).
one-liner with streams
Stream.concat(Arrays.stream( array ), Stream.of( newElement )).toArray();
I have an assignment, in which we have to create a directory which stores names and an extension number. In the first part we have to store the information in just an Array. We have to be able to add an entry to the Array and also initially read a .txt file and store it in the Array. Finally it has to print the Array. I was just wondering what would be more efficient because I only started learning code the last few months and this is difficult for me.
1) Would it be better to first create an Array of size [9999] (because that is the max number of entries the directory could have because everyone has a unique four digit number). I have an INT called count which keeps a count of what the last Array[x] to be added so when I call a method like addEntry, it will add the Entry to [X+1].
The problems with this be is that from what I have read, Arrays are huge and it could have performance problems. Also I have to be able to make a 'lookup' method which should be able to search the Array for someones number by entering their name.
My other option:
2) When the file is read, it counts how many lines the file has (each entry will be on its own line) then creates an Array of the number of lines in the text file. Whenever I want to add a new Entry, I copy the Array into an ArrayList, then back to an Array with the new Entry added. However I also read that copying arrays is not so good too and in a realistic view, if someone was to use this directory they could be adding entries every day.
Aslong as I store in an Array and print the Array into a table it is all good, but what would be the best way to make the actual Array when you don't know the size? (Yes I know I can use ArrayList but its specifically said not to)
Also how would you go about deleting an Entry in the Array, if I use my way there would be a missing entry at Array[x] where x got deleted.
Thanks in advance for any replies.
It is best to initialize an array to the size that you initially need it. When you need to add items to the array after that, you can uses a memory copy rather than an object clone.
int[] arrayOne = new int[20];
int[] arrayTwo = new int[40];
System.arraycopy(arrayOne, 0, arrayTwo, 0, arrayOne.length);
This copy is actually very fast because it just makes a direct copy from memory. This is actually what the underlying code of array list does when it doubles in size.
If you want a "dynamic" sized array, you could write your own version of array list.
For example:
Starts at size 1
Doubles in size when it gets full
shifts objects on a delete using System.arraycopy()
reduces in half when a delete causes size to be less than n/3
I'm trying to make a programme that it doesn't ask user the value i, where i being the number of elements of an array, ( int[] someArray = new int[i]).
Two problems i'm facing , first how the programme auto locates memory size , and second one is, facing trouble with different types of data( i know this one is trivial but just could't put together the logic).
Basically my programme structure is like below:
Scanner input = new Scanner(System.in);
int[] someArray;
int element;
String order;
while(!("done").equals(order=input.nextLine())){
if(some integer){
//set the user input as the value of array element, and change the pointer to the next element
}
if(some string other than "done"){
System.out.println();
//continues the loop
}
}
You can just use an already existing growing collection, such as ArrayList, LinkedList, etc. You add as many elements as you want and they take care of dynamically allocating the necessary space.
This is called dynamic resizing and has the amortized complexity O(n).
The main idea is to double the array size every time your array gets full.
For implementation details I would take a look here.
PS: don't forget to mark some answers for your questions as SOLVED, as it seems that you never do that.
I want to use an ArrayList (or some other collection) like how I would use a standard array.
Specifically, I want it to start with an intial size (say, SIZE), and be able to set elements explicitly right off the bat,
e.g.
array[4] = "stuff";
could be written
array.set(4, "stuff");
However, the following code throws an IndexOutOfBoundsException:
ArrayList<Object> array = new ArrayList<Object>(SIZE);
array.set(4, "stuff"); //wah wahhh
I know there are a couple of ways to do this, but I was wondering if there was one that people like, or perhaps a better collection to use. Currently, I'm using code like the following:
ArrayList<Object> array = new ArrayList<Object>(SIZE);
for(int i = 0; i < SIZE; i++) {
array.add(null);
}
array.set(4, "stuff"); //hooray...
The only reason I even ask is because I am doing this in a loop that could potentially run a bunch of times (tens of thousands). Given that the ArrayList resizing behavior is "not specified," I'd rather it not waste any time resizing itself, or memory on extra, unused spots in the Array that backs it. This may be a moot point, though, since I will be filling the array (almost always every cell in the array) entirely with calls to array.set(), and will never exceed the capacity?
I'd rather just use a normal array, but my specs are requiring me to use a Collection.
The initial capacity means how big the array is. It does not mean there are elements there. So size != capacity.
In fact, you can use an array, and then use Arrays.asList(array) to get a collection.
I recomend a HashMap
HashMap hash = new HasMap();
hash.put(4,"Hi");
Considering that your main point is memory. Then you could manually do what the Java arraylist do, but it doesn't allow you to resize as much you want. So you can do the following:
1) Create a vector.
2) If the vector is full, create a vector with the old vector size + as much you want.
3) Copy all items from the old vector to your new vector.
This way, you will not waste memory.
Or you can implement a List (not vector) struct. I think Java already has one.
Yes, hashmap would be a great ideia.
Other way, you could just start the array with a big capacity for you purpose.