I have come across the below code while searching some answers.
public static void recurse(Scanner in, HashMap<String, Integer> oldMap) {
HashMap<String, Integer> map = null;
if (oldMap == null)
map = new HashMap<String, Integer>();
else
map = new HashMap<String, Integer>(oldMap);
while (in.hasNext) {
String s = in.nextLine();
if (s.startsWith("[")) {
recurse(in, map);
continue;
}
if (s.startsWith("]")) {
break;
}
String[] split = s.split(" ");
if (s.startsWith("print")) {
System.out.println(map.containsKey(split[1]) ? map.get(split[1]) : 0);
continue;
}
int x = 0;
try {
x = Integer.parse(split[1]);
} catch (Exception e) {
x = map.containsKey(split[1]) ? map.get(split[1]) : 0;
}
map.put(split[0], x);
}
}
Can somebody please explain me , why the person has used continue just after recursive call. It seems to be that the continue will not be processed because each time the recursion call will be processed.
It's true that the recursive call will be processed — but then, eventually, the recursive call will return. (Unless it either raises an exception or enters an infinite loop, that is.) After the recursive call returns, the continue statement is executed.
It might help you to play with a simpler example of recursion:
public void printOneToN(int n) {
if(n > 1) {
printOneToN(n - 1);
}
System.out.println(n);
}
As you can see by running (say) printOneToN(10), after each recursive call, control returns to its caller. A recursive call does not replace its caller.
continue has nothing to do with the recursive call; its effect is to skip the rest of the contents of the while loop and go straight back to in.hasNext().
Related
how to add if my data first time exist, value will put 1, if the data already exist into hashmap, need put 2 and so on.
below is my coding:
public ArrayList<String> processJson(JSONObject json) {
HashMap<String, Integer> hm = new HashMap<String, Integer>();
ArrayList<String> output = new ArrayList<>();
for (int i = 0; i < hits.length(); i++) {
// to make sure funny/stupid/illogical resp back from ES is caught and ignored!
try {
JSONArray tag = item.getJSONArray("tag");
System.out.println("tag" + hm.entrySet());
if (source.equalsIgnoreCase("trkd")) {
for (int j = 0; j < tag.length(); j++) {
if (j == 0) {
if (!hm.containsKey(tag.toString(0))) {
hm.put(tag.getString(0), 1);
} else {
hm.put(tag.getString(0), new Integer(j + 1));
}
}
}
}
if (hm.containsValue(1)) {
output.add(out);
} else {
output.add(out);
}
} catch (Exception e) {
e.printStackTrace();
}
}
return output;
}
if the value equal to 1, output just add.
but now, my hashmap all is value 1, how to do?
You are doing the compare on
if (!hm.containsKey(tag.toString(0))) {
but updating with
hm.put(tag.getString(j), 1);
so j != 0
I guess the contains should also be using j
Edit
As #Adi points out
Plus, the check the condition 'j==0', this is unnecessary and prevents you from processing beyond first tag.
Instead of a HashMap, you should use a Multimap. Google Guava provides one.
Lots of weird things going on in your code.
Pretty sure tag.toString(int) and tag.getString(int) are not equivalent. I bet you only wanted to use getString
Why is everything happening in j==0 clause? Your loop would effectively only be doing useful stuff only once.
Were you actually trying to code something like this?
if (!hm.containsKey(tag.getString(j))) {
hm.put(tag.getString(j), 1);
} else {
hm.put(tag.getString(j), hm.get(tag.getString(j)+1);
}
The following code doesn't require an if-else since you're doing the same thing in both cases.
if (hm.containsValue(1)) {
output.add(out);
} else {
output.add(out);
}
Can be replaced with:
output.add(out)
I don't think you're explaining very well what you need to do. From whatever I could gather using my code from #3 should get you exactly what you want.
I have an ArrayList that contains instances of the Staff class. When I write the following code I am told by IntelliJ that the 'for statement does not loop':
public String getTypist() {
String tempTy = "";
for (Staff g : staffList) {
if (g.getStaffID().contains("TY") && g.isAvailable()){
tempTy = g.getStaffID();
}
staffList.remove(g);
staffWorking.add(g);
break;
}
return tempTy;
}
I'm really confused as I thought that this was the way to properly use a for loop on an ArrayList. What am I doing incorrectly with my for loop?
Your for loop contains a break statement which always executes no matter what happens before in the loop, so after the very first looping occurs, the break happens, and nothing else is looped afterwards. This basically makes it as though there was no for loop at all, as executing code one time is the default way a series of statements are executed. Correcting this involves making sure the break executes only some of the loops (specifically, making sure it only executes on the loop you want to be the last loop). Making that correction with the addition of some other fixes you would get code similar to this:
public String getTypist() {
for (Staff s : staffList) {
if (s.getStaffID().contains("TY") && s.isAvailable()){
staffList.remove(s);
staffWorking.add(s);
return s.getStaffID();
}
}
return "";
}
However, there is an alternative solution that would allow you to avoid iterating over the ArrayList at all. You can replace that code with this code and it will work without any for loop because it uses the methods of the ArrayList itself to accomplish the task:
public String getTypist() {
ArrayList<Staff> staffWorking = new ArrayList<>(staffList);
staffWorking.removeIf(staff -> !(staff.isAvailable() && staff.getStaffID().contains("TY")));
staffList.removeAll(staffWorking);
Optional<Staff> typist = staffWorking.stream().findFirst();
if(typist.isPresent()){
return typist.getStaffID();
}else{
return "";
}
}
Though even that could be simplified and improved to this (this code supports concurrent filtering so on multi-processor systems it will be much faster):
private static final Predicate<Staff> isATypistWorker =
staff -> staff.isAvailable() && staff.getStaffID().contains("TY");
public String getTypist() {
ArrayList<Staff> typistWorkers = staffList.stream()
.parallel()
.filter(isATypistWorker)
.distinct()
.collect(Collectors.toCollection(ArrayList::new));
staffList.removeAll(typistWorkers);
staffWorkers.addAll(typistWorkers);
Optional<Staff> typist = typistWorkers.stream().findFirst();
return typist.isPresent() ? typist.getStaffID() : "";
}
You aren't looping because you always break after the first iteration of the loop. I think you need braces around your if statement.
public String getTypist() {
String tempTy = "";
for (Staff g : staffList) {
if (g.getStaffID().contains("TY") && g.isAvailable()) {
tempTy = g.getStaffID();
staffList.remove(g);
staffWorking.add(g);
break;
}
}
return tempTy;
}
Also the code I posted won't work because you can't remove from an ArrayList while looping through it. But that is a different issue.
This is a simple program to check if a number if Fibonnacci. I have a mysterious bug: the "return true" statement isn't triggered. Instead, "hi" will be printed many times. Return should break out of the method, does anyone have insight as to why it's not? Thanks!
import java.util.*;
public class Solution {
public static boolean listFibs (long oldestFib, long oldFib, long input) {
long newFib = oldestFib + oldFib;
while (newFib < Math.pow(10,10)) {
if (newFib == input) {
System.out.println("hi");
return true;
}
listFibs(oldFib, newFib, input);
}
return false;
}
public static void main(String[] args) {
/*Scanner in = new Scanner(System.in);
int testCases = in.nextInt();
for (int i = 0; i < testCases; i++) {
int a = in.nextInt();
System.out.println("A= " + a);
System.out.println(listFibs(0, 1, a));
}*/
System.out.println(listFibs(0, 1, 5));
}
}
Due to the recursion there are many incarnations of listFibs. The return just leaves one of them.
In the example given, you get the following calls:
listFib(0,1,5)
listFib(1,1,5)
listFib(1,2,5)
listFib(2,3,5)
-> true
listFib(2,3,5) // called again due to the loop
-> true
listFib(2,3,5) // called again due to the loop
-> true
listFib(2,3,5) // called again due to the loop
-> true
listFib(2,3,5) // called again due to the loop
...
actually, if "hi" is printed many times, the return statement must be executed the same time. if you install a break point in that return statement, you will see.
your function is a recursion, and "listFibs" will be called many times.
Print values of all 3 variables in the method and you will know what's wrong. You are using recursion, see how many times it's being called.
Also, after call to listFib, execution will go to while loop again. You need to say return listFibs at least. Between your listFibs and while loop condition, nothing is changing. 2,3,5 are being found again and again.
see http://ideone.com/1d440f
You are one step short... The recursive call doesn't do anything with the results you get from listFibs, so the program sees something like this:
while (newFib < Math.pow(10,10)) {
if (newFib == input) {
System.out.println("hi");
return true;
}
true //or false
}
Try adding this extra little IF statement. Once a true result is found it will be passed back up the chain and out of the function.
while (newFib < Math.pow(10,10)) {
if (newFib == input) {
System.out.println("hi");
return true;
}
if listFibs(oldFib, newFib, input){
return true;
}
}
Consider following snippet:
private List<User> getUsers() throws TasteException {
final int MAX_USERS = 100;
List<User> userList = new ArrayList<>(MAX_USERS);
dataModel.getUserIDs().forEachRemaining(userId -> {
if (userList.size() == 100) {
// stop
}
userList.add(new User(userId));
});
return userList;
}
break or return is not working here. What can I do?
The only way to stop the iteration early is to throw an exception. Using exceptions for control flow isn't advised, so I would use Stream.limit, .map, and .collect:
private List<User> getUsers() throws TasteException {
final int MAX_USERS = 100;
return dataModel.getUserIDs()
.stream()
.limit(MAX_USERS)
.map(userId -> new User(userId))
.collect(Collectors.toList());
}
If getUserIDs can't be changed to return Collection you can convert to a Spliterator first:
private List<User> getUsers() throws TasteException {
final int MAX_USERS = 10;
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(dataModel.getUserIDs(), 0), false)
.limit(MAX_USERS)
.map(userId -> new User(userId))
.collect(Collectors.toList());
}
You can 'emulate' a break; adding an if for a boolean check at start of the foreach lambda body, before doing any intensive operation
Note that I used an final Map<Boolean> to hold the boolean flag found as it's a way to declare a boolean 'variable' outside the lambda (you know, it has to be 'final') but be able to set its value in the loop
boolean containsSecret(Iterable<String> values) {
final Map<String, Boolean> scopedLambdaBooleans = new HashMap<String, Boolean>();
scopedLambdaBooleans.put("found", false);
values.forEach(s -> {
if (scopedLambdaBooleans.get("found")) {
return; //just the overhead of a boolean if but a continue before any iteration is very near to the break; performance
}
//Logger.getAnonymousLogger().info(s);
if (secret.equals(s)) {
scopedLambdaBooleans.put("found", true);
}
});
return scopedLambdaBooleans.get("found");
}
The overhead is just a boolean if check at start of any iteration
If you fell guilty for having added an if check, you can compensate getting rid of the internal if:
boolean containsSecretNoInternalIf(Iterable<String> values) {
final Map<String, Boolean> scopedLambdaBooleans = new HashMap<String, Boolean>();
scopedLambdaBooleans.put("found", false);
values.forEach(s -> {
if (scopedLambdaBooleans.get("found")) {
return; //just the overhead of a boolean if but a continue before any iteration is very near to the break; performance
}
Logger.getAnonymousLogger().info(s);
scopedLambdaBooleans.put("found", secret.equals(s));
});
return scopedLambdaBooleans.get("found");
}
Anyway that's writing a boolean 'bit' in memory at any iteration before the finding, I don't know if really better than an 'if' (is the java 'if check' on a .equals using a bit of memory to execute itself or directly cpu registers? uhm.. being on a jvm we should think it like 'Stack vs. Heap' and yes, I think on modern jvm with JIT compilers Stack has optimizations to use directly cpu registers )
Consider using the streams properly, it seems like you want:
dataModel.getUserIDs().stream()
.limit(100)
.forEach(userId -> userList.add(new User(userId)));
This will obtain a stream of the first 100 items and perform an action on them. I cannot give a more detailed answer as I do not know the signature of dataModel.getUserIDs().
Control flow (break, early return) - In the forEach examples above, a traditional continue is possible by placing a "return;" statement within the lambda. However, there is no way to break out of the loop or return a value as the result of the containing method from within the lambda. For example:
final String secret = "foo";
boolean containsSecret(Iterable<String> values) {
values.forEach(s -> {
if (secret.equals(s)) {
??? // want to end the loop and return true, but can't
}
});
}
To see more here is the link : http://www.techempower.com/blog/2013/03/26/everything-about-java-8/
In order to break/exit from forEachRemaining of Scanner instance, close the console input as below once the exit condition is met.
scanner.forEachRemaining(s -> {
if(s.equals("exit")) {
try {
System.in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
parkingLot.execute(s.trim().split(" "));
});
I am in a beginning class for programming and try to combine 2 lists to make one list, putting the new list in numerical order. The part I am having trouble with is, allowing the code to loop, repeating the steps so that it runs through the total original loops to complete the final list which is a combination of all the numbers from the original lists. Any guidance for the loop would be appreciated. Thank you.
import inClass.list.EmptyListException;
import inClass.list.List;
public class InitialLists {
public static void main(String[] args) {
List<Integer> intObject1 = new List<Integer>();{
intObject1.insertAtFront(25);
intObject1.insertAtFront(19);
intObject1.insertAtFront(3);
intObject1.print();}
List<Integer> intObject2 = new List<Integer>();{
intObject2.insertAtFront(120);
intObject2.insertAtFront(1);
intObject2.print();}
List<Integer> combinedList = new List<Integer>();
int object1 = intObject1.removeFromBack();
int object2 = intObject2.removeFromBack();
while(intObject1.removeFromBack() != null && intObject2.removeFromBack() != null){
try {
{
if (intObject1.removeFromBack() > intObject2.removeFromBack()) {
combinedList.insertAtFront(object2);
intObject1.insertAtBack(object1);
}
else if (intObject2.removeFromBack() < intObject1.removeFromBack()) {
combinedList.insertAtFront(object1);
intObject2.insertAtBack(object2);
}
else if (intObject1.removeFromBack() == intObject2.removeFromBack()) {
combinedList.insertAtFront(object1);
}
}
combinedList.print();
object1 = intObject1.removeFromBack();
object2 = intObject2.removeFromBack();
} // end try
catch (EmptyListException emptyListException) {
emptyListException.printStackTrace();
} // end catch
} //end while
} // end main
}// end class
What about:
List<Integer> combinedList = new ArrayList<Integer>();
combinedList.addAll(intObject1);
combinedList.addAll(intObject2);
Collections.sort(combinedList);
Or am I missing something?
To merge two files / lists / streams you need a loop that looks a bit like this
WHILE NOT FINISHED
GET SMALLEST VALUE FROM INPUTS
APPEND SMALLEST VALUE TO OUTPUT
So how will you know that you are finished?
How will you get the smallest of the next item in each list?
The code I have written above is called pseudocode; it is a way of describing the steps of an algorithm. Keep expanding each step until you have pseudocode that you can implement in your chosen language, in this case Java.
Hope that helps ...
I guess your problem is because of possible uneven size of two lists. Try putting while condition as below:
Integer object1 = intObject1.removeFromBack();
Integer object2 = intObject2.removeFromBack();
while(object1 != null || object2!= null){
if(object1 ==null){
//safe to assume object2 is not null as both not null together (that is the termination condition)
combinedList.insertAtFront(object2);
}else if(object2 ==null){
//safe to assume object1 is not null as both not null together (that is the termination condition)
combinedList.insertAtFront(object1);
}else{
//put you normal condition of handling object1 and object2 being not null
if (object1.intValue() > object2.removeFromBack()) {
combinedList.insertAtFront(object2);
intObject1.insertAtBack(object1);
}
else if (object2.intValue() < object1.intValue()) {
combinedList.insertAtFront(object1);
intObject2.insertAtBack(object2);
}
else if (object1.intValue() == object2.intValue()) {
combinedList.insertAtFront(object1);
}
}
object1 = null;
object2 = null;
try{
object1 = intObject1.removeFromBack();
}catch (EmptyListException emptyListException) {
//do nothing
} // end catch
try{
object2 = intObject2.removeFromBack();
}catch (EmptyListException emptyListException) {
//do nothing
} // end catch
}
Also please note: There are better way of doing the merge of two sorted list elements. This approach is advised in light of your little known custom List class.