I'm creating a number of objects with details read in from an array. They will have a standard format for one of their instance variables which I'd like to be, in part, an ascending number. Specifically, I'm creating a load of Location objects which I'd like to have a description of "Flat 1", "Flat 2", etc.
I'm wondering though if there is an easy way to perform addition when assigning a value to a String. Stripped down to the relevant part, my code is:
int size = locations.size();
Location l;
for (int i=0; i<size; i++){
l = new Location ("Flat " + i + 1); //LINE A
addLocation(l);
}
//several bits of code have been removed and swapped around here, I realise
//that that snippet doesn't really perform anything useful
However, Java interprets both the "+" symbols in LINE A as concatenation meaning I get "Flat 01", "Flat 11", "Flat 21", etc.
Obviously I could change around the way the loop works, but I was curious as to whether performing calculations in a myString = value + 2 type statement was possible?
String concatenation is left-associative, so all you have to do is wrap the value you want in parentheses to ensure that it's calculated first:
l = new Location ("Flat " + i + 1);
is effectively:
l = new Location (("Flat " + i) + 1);
So i is appended to the string "Flat " first; and then 1 is appended to that.
Should be:
l = new Location ("Flat " + (i + 1));
Use parentheses:
l = new Location ("Flat " + (i + 1)); //LINE A
Related
I came across several questions but without an answer for my problem.
I have a code camming from data-base in this format: FR000009.
The output should be: FR000010
String original = "FR000009";
String incremented = "FR" + String.format("%0" + (original.length() - 2) + "d",
Integer.parseInt(original.substring(2)) + 1);
System.out.println(incremented);
Here came the difference from other questions: I want to parse the string without the need of hardcoding FR like in the example above. In time there can be different country codes (DE, UK,RO etc).
You need a method where you can pass in the country code and create a new string from the old one.
Your requirement isn't clear. I can't tell if you always want to increment the value, regardless of country code.
I think you need a better abstraction than a String. I don't know what this String is, but I'd recommend a class with a static counter and a method that takes in a country code and returns a String value after incrementing the counter. No parsing needed.
Why not just split between digits and leters:
String input = "FR100109";
String[] splited = input.split("(?<=\\D)(?=\\d)");
int incremented = Integer.parseInt(splited[1]) + 1;
String formated = String.format("%0"+ splited[1].length() + "d", incremented);
System.out.println(splited[0] + formated);
You can use this code by stripping all digits first and then stripping all non-digits:
String original = "FR000009";
String repl = String.format("%s%0" + (original.length() - 2) + "d",
original.replaceFirst("\\d+", ""),
(Integer.valueOf(original.replaceFirst("\\D+", "")) + 1));
//=> "FR000010"
Here:
replaceFirst("\\d+", ""): removes all digits from input, giving us FR
replaceFirst("\\D+", ""): removes all non-digits from input, giving us 000009
Note that if there are always only 2 letters at the start and remaining are digits then you won't even need a regex code, just use substring:
String repl = String.format("%s%0" + (original.length() - 2) + "d",
original.substring(0, 2),
(Integer.valueOf(original.substring(2)) + 1));
I'm building a small app which auto translates boolean queries in Java.
This is the code to find if the query string contains a certain word and if so, it replaces it with the translated value.
int howmanytimes = originalValues.size();
for (int y = 0; y < howmanytimes; y++) {
String originalWord = originalValues.get(y);
System.out.println("original Word = " + originalWord);
if (toReplace.contains(" " + originalWord.toLowerCase() + " ")
|| toCheck.contains('"' + originalWord.toLowerCase() + '"')) {
toReplace = toReplace.replace(originalWord, translatedValues.get(y).toLowerCase());
System.out.println("replaced " + originalWord + " with " + translatedValues.get(y).toLowerCase());
}
System.out.println("to Replace inside loop " + toReplace);
}
The problem is when a query has, for example, '(mykeyword OR "blue mykeyword")' and the translated values are different, for example, mykeyword translates to elpalavra and "blue mykeyword" translates to "elpalavra azul". What happens in this case is that the result string will be '(elpalavra OR "blue elpalavra")' when it should be '(elpalavra OR "elpalavra azul")' . I understand that in the first loop it replaces all keywords and in the second it no longer contains the original value it should for translation.
How can I fix this?
Thank you
you can sort originalValues by size desc. And after that loop through them.
This way you first replace "blue mykeyword" and only after you replace "mykeyword"
The "toCheck" variable is not explained what is for, and in any case the way it is used looks weird (to me at least).
Keeping that aside, one way to answer your request could be this (based only on the requirements you specified):
sort your originalValues, so that the ones with more words are first. The ones that have same number of words, should be ordered from more length to less.
public enum Number {
one(), two(), three(), four();
}
I want to send a message with the numbers separated by a comma:
The numbers are one, two, three and four
The simplest solution would be to use the method name() in your enum
System.out.println(Number.one.name() + ", "
+ Number.two.name() + ", "
+ Number.three.name() + ", "
+ Number.four.name());
Or, if you want to populate your enum in a List first, because your numbers are many, you could populate them using EnumSet.allOf like this:
List<Number> numberList =
new ArrayList<Number>(EnumSet.allOf(Number.class));
And then simply use it like this:
for (int i = 0; i < numberList.size(); i++){
System.out.print(numberList.get(i).name() + (i == numberList.size() - 1 ? "" : ","));
}
(A little syntatical sugar to distinguish between the last number and the rests are added)
I suggest you read the java documentation here:
https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html
I'm looking to see if the difference between every adjacent number in an array is the same as another array, or a rotation of it, for example
A = {1,2,4}, so the differences are {1,1,2}
B = {4,6,7}, the differences are {1,2,1}
If all elements in {1,2,1} were moved clockwise one-element, the result is {1,1,2}, which is correct.
so far I convert the differences to strings, and then see if the differences of the second array is found in the first concatenated with itself
valid if "1 2 1" is in "1 1 2 1 1 2"
my code so far looks like this
count is the length of the array, both have the same length
int c = count - 1;
StringBuilder b1 = new StringBuilder();
StringBuilder b2 = new StringBuilder();
for (int i = 0; i < c; i++) {
b1.append(array1[i + 1] - array1[i]);
b1.append(" ");
b2.append(array2[i + 1] - array2[i]);
b2.append(" ");
}
b1.append((array1[0] - array1[c]) + d);
b1.append(" ");
b2.append((array2[0] - array2[c]) + d);
String a2 = b2.toString();
String a3 = b1.toString() + b1.toString();
System.out.println(a3.contains(a2) ? "valid" : "not valid"); //bottleneck here
My problem is when I use big arrays (up to about 250,000 elements) I get a massive bottleneck at the last line with the .contains(). I'm wondering if there is either a faster way of check if its inside the method than what I'm using, or if I can check while building up the string, or if there is a completely different way of doing this?
You need a more efficient algorithm then the one that is used in contains method(it actually depends on a concrete implementation, but it looks like it is not efficient in the version of Java you are using).
You can use Knuth-Morris-Pratt algorithm: http://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm. It has linear time and space complexity in the worst case so it works fast even for very big arrays. Note that there is no need to convert an array to a string, because this algorithm works for arrays, too.
I have an Android app that allows the user to record data (such as accelerometer, latitude, longitude, etc.). There are a total of 9 of these fields, and the user can record for up to 10 minutes (3000 records per field). Therefore, a total of 27,000 data points can be collected. The user can also take pictures and videos to upload the SD Card as well.
When the user is done collecting data (or the 10 minutes are up), the data is stored in a String, which is later uploaded to the SD Card as a .csv file. The problem though is that it takes forever for the data to append to the string, due to the massive amount of garbage collecting (it appears to be approximately 5 collects or so per second!) The appending starts off fast, but seems to be slowing down as more and more as data is added.
This is the loop that causes the lag:
for( i = 0 ; i < len2 ; i++ ) {
data += accelX[i] + ", " + accelY[i] + ", " + accelZ[i] +
", " + accelT[i] + ", " + latitu[i] + ", " +
longit[i] + ", " + orient[i] + ", " +
magneX[i] + ", " + magneY[i] + ", " + magneZ[i] +
", " + millis[i] + "\n";
partialProg = 100.0 * ( (double)(i+1) / (double)(len2));
dia.setProgress((int) partialProg);
}
data is just a String, and nothing is being newed, so I'm unsure of why GC is being called so often. My question is: what is the problem here, and/or how can I make this more efficient?
You are creating a lot of objects. every time you use the operator+, you actually create a new object, which is expansive [if you repeat it a lot of times]
You can make it more efficient by using a StringBuilder and append to it, and create the String when you are done.
for example:
sb.append(accelX[i]).append(',').append(accelY[i]).append(',').append(accelZ[i]);
[where sb is an instance of StringBuilder]
You could use StringBuilder to concatenate the data:
StringBuilder sb = new StringBuilder();
for( i = 0 ; i < len2 ; i++ ) {
sb.append(accelX[i]).append(", ");
sb.append(accelY[i]).append(", ");
sb.append(accelZ[i]).append(", ");
sb.append(accelT[i]).append(", ");
sb.append(latitu[i]).append(", ");
sb.append(longit[i]).append(", ");
sb.append(orient[i]).append(", ");
sb.append(magneX[i]).append(", ");
sb.append(magneY[i]).append(", ");
sb.append(magneZ[i]).append(", ");
sb.append(millis[i]).append("\n");
}
StringBuilder is inherently faster for building long strings.
It also avoids allocating so many String objects into the heap; since each += operator is creating a new String object rather than modifying the last one. This in turn leads to a large number of GC calls to clean up all the redundent String objects. See also: http://chaoticjava.com/posts/stringbuilder-vs-string/
As Marcelo points out; you may also find dealing with large amounts of data in memory may become problematic on low-spec Android devices, at which point you should consider appending the contents of your StringBuilder to a temporary file every X number of iterations to keep the footprint low. At the end of the process you can stream the file to whatever the destination is planned to be, or read segments of it back to memory on demand.
One improvement you may do is, StringBuffer to construct data, that way you don't you can avoid String construction and concatenation operations. For example:
StringBuffer buff = new StringBuffer();
buff.append(accelX[i]).append(...).apend(...)
+ operator on strings actually uses StringBuilder, thus you do perform at least two allocations per loop (new StringBuilder and then StringBuilder creates a string when .toString() is called on it to assign the result to data).
Best way to tackle this is to create a StringBuilder in front of the loop.
StringBuilder buf = new StringBuilder();
String sep = ", ";
for( i = 0 ; i < len2 ; i++ ) {
buf.append(accelX[i]).append(sep).append(accelY[i]).append(sep);
buf.append(accelZ[i]).append(sep).append(accelT[i]).append(sep);
buf.append(latitu[i]).append(sep).append(longit[i]).append(sep);
buf.append(magneX[i]).append(sep).append(magneY[i]).append(sep);
buf.append(magneZ[i]).append(sep).append(millis[i]).append('\n');
partialProg = 100.0 * ( (double)(i+1) / (double)(len2));
dia.setProgress((int) partialProg);
}