Java - mapping stream variable reassignment - java

Using this stream, I am trying to reassign the variable c inside the stream, in order to map different results each time. I attempted to use a foreach loop outside the stream, however I realized it is made futile as it does not occur within the stream.
I have commented where I am trying to do this.
List<Hills> hills = readHills();
Set<String> countys = new HashSet<>();
for (Hills s: hills) {
countys.add(s.getCounty());
String[] c = new String[0];
c[1] = s.getCounty();
System.out.println("### County: " + c[0]);
hills.stream()
.filter(Hill -> !Hill.getCounty().equals(c[0]))
.map((Hills Hill) -> Hill.getName() + " " + Hill.getHeight())
.forEach(Hill ->{
System.out.println(Hill);
c[0] = Hill.getCounty(); // This is what I am trying to do
});
}

Well your filter most probably filters out all results. If it would not do that, than you would see a lot of java.lang.ArrayIndexOutOfBoundsException: 1 in your output. The problem is here:
String[] c = new String[1];
... some other code
System.out.println(Hill);
c[1] = Hill.getCounty(); // you can only access c[0] here
You are declaring an array of a single element (access it by index zero); but you try to access it by index 1; which does not exist.
Even if you change the code to c[0] = Hill.getCounty(); you would be storing the last result only and because you are using forEach (which says that order is not guaranteed), that might not even mean the last Hill in the list(depending if you might later in the future change that for a parallel stream for example).

Related

Looking for elegant way of searching through an array of strings for duplicate entries. Brute force method works

I have a file of alphanumeric VIN numbers from vehicles (saved as strings). I need to parse through this file and determine
1) Is a VIN duplicated? If so, how many times
2) Write the duplicated VIN and the total number of duplicates to a text file
I have gotten it to work using the brute force method dual nested For loops. Am looking for a more elegant way to parse the strings. I'm using Java 7 in NetBeans 8.2 and it doesn't appear to like using the .set or hashmap.
Constraints
1) The VINs may be in any order
2) The duplicates can be scattered through the file at random
/* a) Open input and output files
*/
try {
inputStream = new BufferedReader(new FileReader(fileName));//csv file
outputStream = new PrintWriter(new FileWriter("DuplicateVINs.txt"));
/* b) Read in file line by line
then slice out the 17 digit VIN from the extra data I don't care about
*/
while ((thisLine = inputStream.readLine()) != null) {
l = thisLine.substring(1, 18);
linesVIN.add(l.split(","));//why does this split have to be here?
}
/*c) Now that the List is full calculate its size and then write to array of strings
*/
String[][] inputArray = new String[linesVIN.size()][];
i=linesVIN.size();
System.out.println(i);
linesVIN.toArray(inputArray);
/* d) Will use two nested For loos to look for duplicates
*/
countj=0;
countk=0;
for (int j = 1;j<=i-1; j++){ //j loop
duplicateVIN=Arrays.toString(inputArray[j]);
for(int k=1;k<=i-1;k++){
if(duplicateVIN.equals(Arrays.toString(inputArray[k]))){
countk=countk+1;
foundFlag=true;
} else{
//
if(countk>=2){
//if(j!=k){
System.out.println(duplicateVIN + countk);
//} // see if removes the first duplicate
}
foundFlag=false;
countk=0;
}
} //ends k loop
countj=j;
} //ends j loop
} //Completes the try
[2q3CDZC90JH1qqqqq], 3
[2q4RC1NG1JR1qqqqq], 4
[2q3CDZC96KH1qqqqq], 2
[1q4PJMDN8KD1qqqqq], 7
I'm using Java 7 in NetBeans 8.2 and it doesn't appear to like using the .set or hashmap.
Your first step should be to figure out what you're doing wrong with a map. A hashmap is the perfect solution for this problem, and is really what you should be using.
Here's a broad example of how the solution would work, using the information you provided.
Map<String,Integer> countMap = new HashMap<String,Integer>();
while ((thisLine = inputStream.readLine()) != null) {
l = thisLine.substring(1, 18);
if(countMap.containsKey(l)){
countMap.put(l, countMap.get(l)+1);
}else{
countMap.put(l,1);
}
}
I'm assuming that the while loop your provided is properly iterating over all VIN numbers.
After this while loop is completed you would just need to output the values of each key, similar to this:
for(String vin : countMap.keySet()){
System.out.println("VIN: "+vin+" COUNT: "+countMap.get(vin));
}
If I've read your problem correctly, there is no need for a nested loop.

How to concat string values in array list

I need to print all arraylist values at a time using concat.
Here is my code:
ArrayList<String> lst = new ArrayList<String>();
lst.add("hi");
lst.add("hello");
Iterator<String> itr = lst.iterator();
String result = null;
while(itr.hasNext()) {
Object element = itr.next();
result = element + " ";
}
System.out.println(result);
The expected result should be hi hello.
The current output however is hello (there is also a whitespace at the end).
Please prefer the List interface to the ArrayList concrete type. Assuming you are using Java 8+, you might use a Stream and Collectors.joining (and Arrays.asList) like
List<String> lst = Arrays.asList("hi", "hello");
String r = lst.stream().collect(Collectors.joining(" "));
System.out.println(r);
Which outputs
hi hello
As requested.
The error in your code is pretty small. In each iteration you assign a value to the result variable. However instead of updating your existing content you just erase it and enter a new value.
You do result = element + " ". But it should be something like result = result + element + " " or the same in short:
result += element + " ";
This way the first iteration will save hi in it and after that hello gets appended resulting in hi hello (instead of overriding the content of the first iteration).
Note that it now also has the whitespace at the end. You could delete it with result = result.substring(0, result.length() - 1). Or not add it in the last iteration, but then you need to count the iterations.
Please note that Java has a class StringJoiner that does exactly what you want, joining some elements together and also using a delimiter like whitespace. You use it like this:
StringJoiner sj = new StringJoiner(" ");
while(itr.hasNext()) {
Object element = itr.next();
sj.add(element);
}
String result = sj.toString();
Also note that since Java 8 there is an even shorter version of it:
String result = String.join(" ", list);

Executing code N times and other code N+1 times

The question is about while-loops in which I need some code to be executed N times and some other code N+1 times. NOT about concatening Strings, I just use this as bad-coded yet short example.
Let me explain my question by providing an example.
Say I want to concatenate N+1 Strings, by glueing them with "\n", for example. I will have N+1 lines of text then, but I only need to add N times "\n".
Is there any boilerplate solution for this type of loop in which you have to execute some code N times and other code N+1 times? I'm NOT asking for solution to concatenate Strings! That is just a (bad) example. I'm looking for the general solution.
The problem I have with this is code duplication, so to code my example I'll do this (bad pseudo code, I know I have to use StringBuilder etc.):
String[] lines = <some array of dimension N+1>;
String total = lines[0];
for (int i = 1; i < N + 1; i++){
total += "\n" + lines[i];
}
The problem becomes worse if the code that has to be executed N+1 times, becomes larger, of course. Then I would do something like
codeA(); // adding the line of text
for (int i = 1; i < N + 1; i++){
codeB(); // adding the "\n"
codeA();
}
To remove the duplication, you can do this different by checking inside the loop, too, but then I find this quite stupid as I know beforehand that the check is pre-determined, as it will only be false the first iteration:
for (int i = 0; i < N + 1; i++){
if (i > 0){
codeB(); // adding the "\n"
}
codeA();
}
Is there any solution for this, a sort of while-loop that initializes once with codeA() en then keeps looping over codeB() and codeA()?
People must have run into this before, I guess. Just wondering if there are any beautiful solutions for this.
To my dissapointment, I believe that there is no such construct that satisfies the conditions as you have stated them and I will attempt to explain why (though I can't prove it in a strictly mathematical way).
The requirements of the problem are:
We have two parts of code: codeA() and codeB()
The two parts are executed a different number of times, N and N+1
We want to avoid adding a condition inside the loop
We want to execute each part only as many times as strictly necessary
2) is a direct consequence of 1). If we didn't have two parts of code we would not need a different number of executions. We would have a single loop body.
4) is again a consequence of 1). There is no redundant execution if we have a single loop body. We can control its execution through the loop's condition
So the restrictions are basically 1) and 3).
Now inside the loop we need to answer two questions on each iteration: a) do we execute codeA()? and b) do we execute codeB()? We simply do not have enough information to decide since we only have a single condition (the condition of the loop) and that condition will be used to decide if both of the code parts would be executed or not.
So we need to break 1) and/or 3) Either we add the extra condition inside the loop or we delegate the decision to some other code (thus not having two parts anymore).
Apparently an example of delegation could be (I am using the string concatenation example):
String [] lines = ...
for (int i = 0; i < N; i++){
// delegate to a utility class LineBuilder (perhaps an extension of StringBuilder) to concatenate lines
// this class would still need to check a condition e.g. for the first line to skip the "\n"
// since we have delegated the decisions we do not have two code parts inside the loop
lineBuilder.addLine( lines[i] );
}
Now a more interesting case of delegation would be if we could delegate the decision to the data itself (this might worth keeping in mind). Example:
List<Line> lines = Arrays.asList(
new FirstLine("Every"), // note this class is different
new Line("word"),
new Line("on"),
new Line("separate"),
new Line("line") );
StringBuffer sb = new StringBuffer();
for (Line l : lines) {
// Again the decision is delegated. Data knows how to print itself
// Line would return: "\n" + s
// FirstLine would return: s
sb.append( l.getPrintVersion() );
}
Of course all of the above does not mean that you couldn't implement a class that tries to solve the problem. I believe though this is beyond the scope of your original question not to mention that would be an overkill for simple loops
Concatenating Strings like this is a bad idea and a much bigger issue IMHO.
However to answer your question I would do
String sep = "";
StringBuilder sb= new StringBuilder();
for(String s: lines) {
sb.append(sep).append(s);
sep = "\n";
}
String all = sb.toString();
Note: there is usually a good way to avoid needing to create this String at all such a processing the lines as you get them. It is hard to say without more context.
This kind of thing is fairly common, like when you build sql. This is the pattern that I follow:
String[] lines ...//init somehow;
String total = lines[0];
boolean firstTime = true;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++){
if(firstTime) firstTime = false;
else sb.append('\n');
sb.append(lines[i]);
}
Note that this is not the same, as the first example and here is why:
String[] lines = <some array of dimension N+1>;
String total = lines[0];
for (int i = 1; i < N + 1; i++){
total += "\n" + lines[i];
}
Assuming you have an array of [0] = 'line1' and [1] = 'line2'
Here you end up with line1line2\n, when the desired output is:
line1\nline2.
The example I provided is clear, and does not perform poorly. In fact a much bigger performance gain is made by utilizing StringBuilder/Buffer. Having clear code is essential for the pro.
Personally i have most of the time the same problem, on the String example i use the StringBuilder as you said, and just delete the characters added to much:
StringBuilder sb = new StringBuilder();
for(int i=0; i<N; i++) {
sb.append(array[i]).append("\n");
}
sb.delete(sb.length-1, sb.length); // maybe check if sb contains something
In the common case i suppose there is no other way than adding the if you suggested. To make the code more clear i would check at the end of the for loop:
StringBuilder sb = new StringBuilder();
for(int i=0; i<N; i++) {
sb.append(array[i]);
if(i < N) {
sb.append("\n");
}
}
But i totally agree this is sad to have this double logic

Java loop to collect the second and third elements every three in an array

I have a file with data in the form timestamp, coordinate, coordinate, seperated by spaces, as here;
14:25:01.215 370.0 333.0
I need to loop through and add the coordinates only to an array. The data from the file is read in and put into as String[] called info, from split(" "). I have two problems, I think the end of the file has a extra " " which I need to lose appropriately and I also want confirmation/suggestions of my loop, at the moment I am getting sporadic out of bounds exceptions. My loop is as follows;
String[] info;
info = dataHolder.split(" ");
ArrayList<String> coOrds1 = new ArrayList<String>();
for (int counter = 0; counter < info.length; counter = counter+3)
{
coOrds1.add(info[counter+1]);
coOrds1.add(info[counter+2]);
}
Help and suggestions appreciated.
The text file is here but the class receives in a UDP packet from another class so I am unsure if this potentially adds " " at the end or not.
There are various classes/methods in Google's Guava library that could help with this task, in particular Splitter.omitEmptyStrings() which will discard any trailing space at the end of the file:
String input = Files.toString(file, Charsets.US_ASCII);
Iterable<String> fields =
Splitter.on(" ")
.omitEmptyStrings()
.split(input);
List<Coord> coords = Lists.newArrayList();
for (List<String> group: Iterables.partition(fields, 3)) {
String t = group.get(0);
double x = Double.parseDouble(group.get(1));
double y = Double.parseDouble(group.get(2));
coords.add(new Coord(t, x, y));
}
The problem will occur if you have an extra space at the end, because you are testing for counter < info.length and using counter + 1 and counter + 2. Try changing the loop conditions to:
for (int counter = 0; counter + 2 < info.length; counter = counter+3)
There is no need for external libraries.
You could just call dataHolder.trim(); which will remove any whitespace from the beginning and end your string. Then using dataHolder.split("\s"); //splits on "whitespace", you will receive an array consisting only of your data and with the appropriate size.
This will save you all the checks at each iteration whether counter+2 is still within the scope of the array. While still a valid solution, this could introduce further problems in the future due to its inherent nature of being "check-to-validate" - you simply might forget to process one of the cases - while trimming the string beforehand makes it structurally, constructed valid and there is no need to process special cases.

java.lang.IndexOutOfBoundsException: Index: 4, Size: 4

How can I fix this OutOfBoundsException?
Here is the code I am using:
ResultSet rsTagCheck = stmt.executeQuery(
"SELECT PARKING.XKRPRMT.XKRPRMT_PIDM, PARKING.XKRPRMT.XKRPRMT_STATUS, PARKING.XKRPRMT.XKRPRMT_EXPIRE_YR, PARKING.XKRPRMT.XKRPRMT_TAG FROM PARKING.XKRPRMT WHERE XKRPRMT_PIDM ='" + BannerID + "'");
while (rsTagCheck.next()){
String TagNum = rsTagCheck.getString("XKRPRMT_TAG");
ArrayList<String> myTag = new ArrayList<String>();
for (int i = 0; i < TagNum.length(); i++){
myTag.add(TagNum);
myTag.get(i + i);
I kinda know why I am getting the error, but I am not sure how to remedy the problem.
The problem is the i+i part in myTag.get(i+i). It'll work for i=0, but as soon as i=1, you'll get an exception thrown, since you've added two elements to myTag, but are accessing the third element (myTag.get(2)).
What is it that you expect myTag.get(i + i) to do?
The first time through the loop, "i" is zero and you add one element. There won't be an element 1, so the call will throw an exception. Now that I actually see what you wrote, it'll fail on the second iteration, not the first, as poor #Giu noted in his now-deleted answer. Still, it's weird and I don't know what you're trying to accomplish by calling .get() and not even looking at the return value.
You really will have to explain what it is you're trying to do, because that doesn't really make any sense as written. Did the exception in the question title really come from that code, or did you edit part of it out when posting?
edit — whoops totally saw "i+i" as "i+1". Still makes no sense to me however.
You are using the for loop by iterating on the String TagNum. You should only need to say: myTag.add(TagNum).
Imagine that the String TagNum has 4 characters. You add the String to the list 4 times, but when you reach i = 3, you are trying to retrieve the element at position 3 + 1, but the list has elements from 0 to 3.
Also, try replacing the BannerID with a ? and set the parameter to the statement accordingly.
This myTag.get(i + i); is causing the exception.
First time in the loop i is 0, you add an item into the ArrayList and then call get(0+0) which is fine.
In the next iteration, you add another element(total of 2 element in the list now) and call get(1+1), this causes exception as you have only 2 elements and valid index are 0 and 1.
Even without the problem with the get, your program as written will read through the results of the query, and then for each CHARACTER in tagNum, it will add an instance of tagNum to your array. So if tagNum is, say, "ABC", the array will end up containing "ABC" three times. If tagNum is "ABCD", it will contain "ABCD" four times. This doesn't make a lot of sense.
I think what you want is to just add tagNum to an array, defining the array OUTSIDE of the ResultSet.next loop. Something like this maybe:
ArrayList<String> myTag = new ArrayList<String>();
ResultSet rsTagCheck = stmt.executeQuery(
"SELECT PARKING.XKRPRMT.XKRPRMT_PIDM, PARKING.XKRPRMT.XKRPRMT_STATUS, PARKING.XKRPRMT.XKRPRMT_EXPIRE_YR, PARKING.XKRPRMT.XKRPRMT_TAG FROM PARKING.XKRPRMT WHERE XKRPRMT_PIDM ='" + BannerID + "'");
while (rsTagCheck.next()){
String TagNum = rsTagCheck.getString("XKRPRMT_TAG");
myTag.add(TagNum);
}
(Of course this doesn't use any of the other data in your query and I don't know what all else you're up to, but I believe that's what you're trying to do for this part.)
Update
Suppose you have ten records in your database table. After the above loop is complete, the array should be populated.
Try something like this:
ArrayList<String> myTag = new ArrayList<String>();
ResultSet rsTagCheck = stmt.executeQuery(
"SELECT PARKING.XKRPRMT.XKRPRMT_PIDM, PARKING.XKRPRMT.XKRPRMT_STATUS, PARKING.XKRPRMT.XKRPRMT_EXPIRE_YR, PARKING.XKRPRMT.XKRPRMT_TAG FROM PARKING.XKRPRMT WHERE XKRPRMT_PIDM ='" + BannerID + "'");
while (rsTagCheck.next()){
String TagNum = rsTagCheck.getString("XKRPRMT_TAG");
myTag.add(TagNum);
}
for (String tag : myTag)
{
System.out.println(tag);
}
That should give you the list of all the tags. Note you have to examine the List AFTER the while(ResultSet) loop ends. Inside the loop you will only have the elements read so far.
If you're still getting only one value, make sure that you have more than one record coming back from the result set. Like, run the query outside of a Java program and see how many records you get.
List<WebElement> div1=driver.findElements(By.xpath(".//*[#class='art_title']"));
for(int i=0;i<=div1.size();i++)
{
System.out.println(div1.get(i).getText());
Thread.sleep(1000);
}
Instead of the above format I changed it into this format :
List<WebElement> div1=driver.findElements(By.xpath(".//*[#class='art_title']"));
String[] abc = new String[div1.size()];
int i= 0;
for (WebElement e : div1)
{
abc[i] = e.getText();
i++;
System.out.println(e.getText());
}

Categories