I just used the
ArrayList <ArrayList<String>> list = new ArrayList<ArrayList<String>>();
method for the first time and the output wasn't exactly in the way I wanted it to be.
I'm trying to make lists of different students and sorting them by what grade they're in. But, I am also trying to have a list that displays all the students, regardless of their grade. So this is the code that I was using:
ArrayList <ArrayList<String>> allStudents = new ArrayList<ArrayList<String>>();
ArrayList <String> gradeNines = new ArrayList();
ArrayList <String> gradeTens = new ArrayList();
ArrayList <String> gradeElevens = new ArrayList();
ArrayList <String> gradeTwelves = new ArrayList();
boolean firstSelection = true;
public void grade(String a, String b, ArrayList c)
{
a = jComboBox1.getSelectedItem() + "";
if (a.equals(b))
{
studentOutput.setText("");
int x = 0;
for (int indexNum = 0; indexNum < c.size(); indexNum++)
{
x = indexNum + 1;
studentOutput.append(num + ". " + c.get(indexNum) + "\n");
}
}
}
private void jComboBox1ActionPerformed(java.awt.event.ActionEvent evt) {
String studentGrade = jComboBox1.getSelectedItem() + "";
String all = "All Grades";
String nine = "Grade Nine";
String ten = "Grade Ten";
String eleven = "Grade Eleven";
String twelve = "Grade Twelve";
if (firstSelection)
{
Collections.addAll(allStudents, gradeNines, gradeTens, gradeElevens, gradeTwelves);
Collections.addAll(gradeNines, "Oscar", "Justin",....);
Collections.addAll(gradeTens, "Austin", "Jacob", "Evie"....);
Collections.addAll(gradeElevens, "Olivia", "Elizabeth"...);
Collections.addAll(gradeTwelves, "Ryan", "Jade"...);
firstSelection = false;
}
grade(studentGrade, all, allStudents);
grade(studentGrade, nine, gradeNines);
grade(studentGrade, ten, gradeTens);
grade(studentGrade, eleven, gradeElevens);
grade(studentGrade, twelve, gradeTwelves);
But the way this outputted, it was like:
[Oscar, Justin] 2. [Austin, Jacob, Evie] 3. [Olivia, Elizabeth] 4. [Ryan, Jade]
Is there a way to make it so that it outputs so that it shows each name individually like:
Oscar 2. Justin 3. Austin 4. Jacob ...
Firstly, these type of "grouping" problems are better handled using a Map (HashMap or an ordered implementation).
You could have the grades as the key and the list of student names as the values. That would feel as a better and easier way to handle collection data than a nested ArrayList.
Regarding your question,
Is there a way to make it so that it outputs so that it shows each name individually
No. These are separate ArrayLists. You will need to add/display them together, explicitly.
Further, I suggest you use the groupingBy function of Streams in Java 8. That will fit your use case very well.
With Streams, you could choose to display all items together OR group them by grades and display based on the chosen crteria(grade).
See this SO answer: https://stackoverflow.com/a/30202075/599851
Related
Alright so I'm working on a program that reads a periodic table and you can search elements based on number or abbreviation.
Anyway, I'm a bit stuck trying to read the periodic table file into 4 different arrays: Atomic Number, Abbreviation, Element Name, and Atomic Weight.
I dunno how to write a single method to import all that info into each array in one go. I want to have a class that holds all these arrays and that I can call to later when I need each one.
Here is what I got so far, I'm a bit rusty by the way... I thought working on this program would refamiliarize me with the basics.
class PeriodicTable{
private String fileName = "periodictable.dat";
private int[] atomicNumTable = new int[200];
private String[] abbreviationTable = new String[200];
private String[] nameTable = new String[200];
private double[] atomicWeightTable = new double[200];
PeriodicTable(String fileName){
readTable(fileName);
}
public int[] readTable(String fileName){
Scanner inFile = null;
try{
inFile = new Scanner(new File(fileName));
}catch(FileNotFoundException nf){
System.out.println(fileName + " not found");
System.exit(0);
}
atomicNumTable = new int[200];
int i = 0;
while(inFile.hasNext() && i < atomicNumTable.length){
int number = inFile.nextInt();
atomicNumTable[i] = number;
i++;
}
inFile.close();
return atomicNumTable;
}
}
Here is what each line of the table looks like:
1 H Hydrogen 1.00794
Simply use java.lang.String.split(' ') (assuming that your columns are separated using spaces; if it is using something else; you just need to adapt that regular expression parameter!)
That will return an array of Strings; and you basically now: first column should be an int, then you got two Strings, and then a double value. Or lets be precise: you get strings, that mean something else; thus you have to look into methods like Integer.valueOf(); and similar for Double.
Shouldn't be too hard to work your way from there.
But I recommend some changes to your logic: having 4 different tables doesn't make sense at all. Good OO programming is about creating helpful abstractions. Without abstractions, your program becomes abstract itself.
Meaning: you should introduce a class like
public class Element {
private final int id;
private final String abbreviation;
private final String fullName;
private final double atomicWeight;
... with one constructor that takes all 4 parameters
... with getter methods for the fields of this class
... and meaningful overrides for equals() and hashcode()
}
And then, instead of creating 4 arrays; you create one array, or even better an ArrayList<Element>. And instead of pushing your 4 values into 4 different arrays, you create one new Element object in each loop iteration; and you add that new object to your list.
The major difference to your solution would be: you can deal with Elements as a whole; whereas in your solution, a single "Element" is basically an index that points into 4 different tables.
You can simplify this code a lot. Try something like this.
1) Read the file line by line, split lines as you go,
add values to some ArrayList containing String[]
2) Close your file
3) Turn the ArrayList into a String[][]
4) Print the result
Also, note that arrays in Java are indexed starting at 0 not at 1.
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Arrays;
public class Test {
static public void main(String[] args) throws Exception {
File file = new File("periodictable.dat");
FileReader reader = new FileReader(file);
BufferedReader buffReader = new BufferedReader(reader);
String s = null;
ArrayList<String[]> lst = new ArrayList<String[]>();
String[][] res = null;
while((s = buffReader.readLine()) != null){
String[] arr = s.split("[\\s]+");
lst.add(arr);
}
buffReader.close();
res = new String[lst.size()][lst.get(0).length];
res = lst.toArray(res);
System.out.println();
// System.out.println(res);
// String result = Arrays.deepToString(res);
// System.out.println(result);
System.out.println();
for (int i=0; i<res.length; i++){
for (int j=0; j<res[i].length; j++){
System.out.println("res[" + (i+1) + "][" + (j+1) + "]=" + res[i][j]);
}
}
System.out.println();
}
}
OUTPUT:
res[1][1]=1
res[1][2]=H
res[1][3]=Hydrogen
res[1][4]=1.00794
value iterates indexing for each line
You can distinguish four cases in the loop:
i%4 == 0
i%4 == 1
i%4 == 2
i%4 == 3
Depending on this you know the kind of next value you have to read. So, you can search you an integer, string or floating point number and put the value in the right place.
I support the recommendation of GhostCat to only have one array and a class that contains all four values of a line instead of having four arrays.
Why am I getting this problem when trying to print it out? What I'm trying to do is display out the name that was placed in the array.
ArrayList <Employee> empArray = new ArrayList();
LinkedList empyrIncm = new LinkedList();
ListIterator li = empyrIncm.listIterator();
DecimalFormat df = new DecimalFormat ("#, ##0.00");
for (int i = 0; i<empArray.size(); i++)
{
double yrIncm = empArray.get(i).getSalary() * 12;
if (yrIncm > 80000)
{
empyrIncm.add (new String (empArray.get(i).getEmpName()));
while(li.hasNext())
{
System.out.println ("\nName : " + li.next() + "\nTotal yearly income : " + df.format (yrIncm));
}
}
else
{
foundyrIncm = false;
}
}
From what I know, the iterator I used is to display out the name "one-by-one" without the "comma" when more input are added to the array. Means, without the use of iterator, it will display out by default
Name : Object1, Object 2, Object 3, Object 4
Total yearly income : 123
I don't want that comma, instead I want the name to be display out one by one with their yearly income. Any help would be appreciated.
Try initializing the ListIterator just outside the while loop.
ArrayList <Employee> empArray = new ArrayList();
LinkedList empyrIncm = new LinkedList();
DecimalFormat df = new DecimalFormat ("#, ##0.00");
for (int i = 0; i<empArray.size(); i++)
{
double yrIncm = empArray.get(i).getSalary() * 12;
if (yrIncm > 80000)
{
empyrIncm.add (new String (empArray.get(i).getEmpName()));
ListIterator li = empyrIncm.listIterator();
while(li.hasNext())
{
System.out.println ("\nName : " + li.next() + "\nTotal yearly income : " + df.format (yrIncm));
}
}
else
{
foundyrIncm = false;
}
}
You are adding element to the list here:
empyrIncm.add (new String (empArray.get(i).getEmpName()));
while you are iterating the list here:
System.out.println ("\nName : " + li.next() + "\nTotal yearly income : " + df.format (yrIncm));
The iterator in java are Fail-fast. It will not allow you to update the list while iterating over it.
You need to use CopyOnWriteArrayList instead of LinkedList. Normally CopyOnWriteArrayList is very expensive because it involves costly Array copy with every write operation. Use the below statement.
CopyOnWriteArrayList empyrIncm = new CopyOnWriteArrayList();
Also your iterator getting call will be postponed until you need it. Just before the while loop.
ListIterator li = empyrIncm.listIterator();
You cant do following two line's activity together i.e.read & write together with regular fail-fast iterator data structures :-
empyrIncm.add (new String (empArray.get(i).getEmpName()));
while(li.hasNext())
If you want to do both read & write together then do either of the following :-
empyrIncm.add (new String (empArray.get(i).getEmpName()));
ListIterator li = empyrIncm.listIterator();
while(li.hasNext())
OR
Use CopyOnWriteArrayList instead of LinkedList/ArrayList.
Now if you try to print any list then default implementation provided by API prints all element in list by comma seperated, hence the output you getting.
hello I am beginner to work with java. I have following code, where I wanted to initialize the string array word[] dynamically consisting of size of total no. of tokens in all documents [] array.
how should I do that?
String []result = {"Shipment of Gold damaged in fire","Delivery of silver arrived in silver truck","shipment of Gold arrived in Truck"};
String []documents = new String[result.length];
for (int k =0; k<result.length; ++k){
documents[k] = result[k].toLowerCase();
System.out.println("document["+k+"] :" + documents[k]);
}
/*step 2: Tokenize all documents and create vocabulary from it*/
int i=0;
String [] word = new String [30]; // how to do dynamic allocation here
int no_of_tokens=0;
for(String document:documents){
StringTokenizer st = new StringTokenizer(document," ");
System.out.print("tokens in document"+ i +":"+ st.countTokens()+"\n");
while(st.hasMoreTokens()) {
word[no_of_tokens]=st.nextToken();
System.out.print(word[no_of_tokens] + "\n");
no_of_tokens++;
}
i++;
}
Either use a List such as ArrayList, or use String.split() instead of StringTokenizer, it will return a String[].
I would use a java.util.ArrayList instead of a static array. You can't resize a static array, but you can create a new, bigger, static array and then copy the initial contents over.
You can use an implementation of the List interface, like ArrayList for this case. It will resize automatically when it almost fills so you don't have to worry about figuring the right initial size.
You use it like this:
....
/*step 2: Tokenize all documents and create vocabulary from it*/
int i=0;
List<String> word = new ArrayList<String>(); // how to do dynamic allocation here
int no_of_tokens=0;
....
while(st.hasMoreTokens()) {
word.add(st.nextToken());
System.out.print(word.get(no_of_tokens) + "\n");
no_of_tokens++;
}
You may use ArrayList<String> or LinkedList<String>. The two differ in the overhead for adding elements (LinkedList is fast, ArrayList is slow) and getting elements via get(i) (LinkedList is slow, ArrayList is fast).
What would be the easiest / quickest way to zip a list of strings which is similar to this:
john,barry,stewart,josh,30,45,23,56
I want the order to be
john,30,barry,45,stewart,23,josh,56
I know that sounds like homework but the actual list is used in some selenium code and stores urls and the option of a radio button on the page but I thought the above example is simpler to read.
I would do something similar to this:
String[] parts = input.split(",");
int halfLength = parts.length / 2;
for (int i = 0; i < halfLength; i++) {
String name = parts[i];
String age = parts[i + halfLength];
// Store them in whatever structure you want here
}
What you need here is a zip function like in functional languages.
Functional java may help you out.
Related: Is there an accepted Java equivalent to Python's zip()?
Your question sounds like you need code to fix a bad design. Therefore, I would go a step back and ask the question how the list
john,barry,stewart,josh,30,45,23,56
was created, when you obviously need:
(john, 30), (barry, 45), (stewart, 23), (josh, 56)
(Replace the (x,y) notation with you favorite tuple type.)
Here you need to do some manual code.
Firstly scatter all the string and integer separately and obtain two list.
then just iterate one list and add these two list in one final list like first string and
then integer.
Looks like two lists
First generate two lists and create a new result list
Pseudocode :
list = Arrays.AsList(string.split("\\s+"))
list1 = list.sublist(0, list.size() /2 );
list2 = list.sublist(list.size() /2 +1 , list.size());
for(int i = 0;i<list1.size() ; i++ ) {
resultlist.add(list1.get(i);
resultlist.add(list2.get(i);
}
return resultlist
Try this way :
1. First sort it - the numbers will cover half the list and names half the list.
2. Create two arrays half the length : sArr1 and sArr2. Store numbers in sArr1 and names in sArr2.
3. Merge them by putting alternatively the number and the name from the two arrays into original array.
import java.util.Arrays;
public class SortMix {
public static void main(String[] args) {
String sArr[] = {"john","barry","stewart","josh","30","45","23","56"};
Arrays.sort(sArr);
display(sArr);
String sArr1[] = new String[sArr.length/2];
for(int i=0;i<sArr.length/2;i++)
sArr1[i] = sArr[i];
display(sArr1);
String sArr2[] = new String[sArr.length/2];
for(int i=0;i<sArr.length/2;i++)
sArr2[i] = sArr[i+sArr.length/2];
display(sArr2);
int k=0;
int l=0;
for(int i=0;i<sArr.length;i++) {
if(i%2==0){
sArr[i]=sArr1[k];
k++;
} else {
sArr[i]=sArr2[l];
l++;
}
}
display(sArr);
}
public static void display(String[] sArr) {
for(int i=0;i<sArr.length;i++)
System.out.print(sArr[i] + " ");
System.out.println();
}
}
Output would be :
23 30 45 56 barry john josh stewart
23 30 45 56
barry john josh stewart
23 barry 30 john 45 josh 56 stewart
Generic version of zip:
#SafeVarargs
public static <T> ArrayList<T> zip(Iterable<T> ...iterables) {
ArrayList<Iterator<T>> is = new ArrayList<>(iterables.length);
for (int i=0; i<iterables.length; i++) {
is.add(iterables[i].iterator());
}
ArrayList<T> al = new ArrayList<>();
while (is.get(0).hasNext()) {
for (int i=0; i<is.size(); i++) {
// FIXME: could check for shorter-than-expected sublists here
al.add(is.get(i).next());
}
}
return al;
}
Can be tested / called as follows:
public static void main(String[] args) {
List<String> parts =
Arrays.asList("john,barry,stewart,josh,30,45,23,56".split(","));
List<String> names = parts.subList(0, parts.size()/2);
List<String> numbers = parts.subList(parts.size()/2, parts.size());
System.err.println(zip(names, numbers));
}
It seems as if you are just trying to interleave the numbers and the alphanumerics. I would just scan the list in order to find the index of the first number than create a new list and take the first alpha and the first number and add them to the new list, then the second alpha and second number. This is not sorting and so is O(n)
I have a small issue when I run into while using arraylists in Java. Essentially I am hoping to store an array in an arraylist. I know that arraylists can hold objects, so it should be possible, but I am not sure how.
For the most part my arraylist (which is parsed from a file) is just holding one character as a string, but once in a while it has a series of characters, like this:
myarray
0 a
1 a
2 d
3 g
4 d
5 f,s,t
6 r
Most of the time the only character I would care about in the string residing at position 5 is the f but occasionally I may need to look at the s or the t as well. My solution to this is to make an array like this:
subarray
0 f
1 s
2 t
and store subarray in position 5 instead.
myarray
0 a
1 a
2 d
3 g
4 d
5 subarray[f,s,t]
6 r
I tried to do this with this code:
//for the length of the arraylist
for(int al = 0; al < myarray.size(); al++){
//check the size of the string
String value = myarray.get(al);
int strsz = value.length();
prse = value.split(dlmcma);
//if it is bigger than 1 then use a subarray
if(strsz > 1){
subarray[0] = prse[0];
subarray[1] = prse[1];
subarray[2] = prse[2];
}
//set subarray to the location of the string that was too long
//this is where it all goes horribly wrong
alt4.set(al, subarray[]);
}
This isn't working the way I would like though. It won't allow me to .set(int, array). It only allows .set(int, string). Does anyone have suggestions?
The easiest approach would be to have an ArrayList of ArrayList.
ArrayList<ArrayList<String>> alt4 = new ArrayList<ArrayList<String>>();
However, this probably isn't the best solution. You may want to rethink your data model and look for a better solution.
Just change alt4.set(al, subarray[]); to
alt4.add(subarray);
I assume alt4 is another defined ArrayList<String[]>. If not, define it as below:
List<String[]> alt4= new ArrayList<String[]>();
or
ArrayList<String[]> alt4= new ArrayList<String[]>();
My guess is that you are declaring alt4 as List<String> and that's why it is not letting you set an array of String as a list element. You should declare it as List<String[]> and is each element is only singular, simply set it as the 0th element of the String[] array before adding it to the list.
You could switch to:
List<List<Character>> alt4 = new ArrayList<List<Character>>();
May be this is what you want to get
public class Tester {
List<String> myArrays = Arrays.asList(new String[] { "a", "a", "d", "g", "d", "f,s,t", "r" });
ArrayList<ArrayList<String>> alt4 = new ArrayList<ArrayList<String>>();
private void manageArray() {
// for the length of the arraylist
ArrayList<String> subarray = new ArrayList<String>();
for(int al = 0; al < myArrays.size(); al++) {
// check the size of the string
String value = myArrays.get(al);
int strsz = value.length();
String prse[] = value.split(",");
// if it is bigger than 1 then use a subarray
if(strsz > 1) {
for(String string : prse) {
subarray.add(string);
}
}
// set subarray to the location of the string that was too long
// this is where it all goes horribly wrong
alt4.set(al, subarray);
}
}
}