Fastest way to store char[][] in shared preferences - java

In my app, the main set of data is a two-dimensional char array (char[][]), in which some of the values may be non-printable characters and even \0 characters. What would be the fastest way to store this array in the shared prefs and retrieve it later? Speed of retrieval is a lot more important to me than the speed of saving it. The arrays are not particularly large, probably no more than 100x100.
Presently, I'm converting it into a string by simply concatenating all characters, row-by-row, column-by-column, and storing the string along with the dimensions (as int).
I have also considered just serialising the array (writeObject into a ByteArrayOutputStreram and then use the stream's toString method), but haven't tried it yet.
Any other suggestions? Again, the fastest possible retrieval (and recreation as the char[][] array) is my primary concern.

I posted you a way which uses many native functions and therefore is likely fast. Be aware that this is untested and shall only be used inspirational.
public void save(char[][] chars) {
Set<String> strings = new LinkedHashSet<String>(chars.length);
for(int i = 0, len = chars.length; i < len; i++) {
strings[i] = new String(chars[i]);
}
getSharedPreferences().edit().putStringSet("data", strings).commit();
}
public char[][] read() {
Set<String> strings = getSharedPreferences().getStringSet("data", new LinkedHashSet<String>());
char[][] chars = new char[strings.size][];
int i = 0;
for(String line : strings) {
chars[i++] = line.toCharArray();
}
return chars;
}

Because StringSet methods (put and get) are only available from Android 3.0 and also because I found the preferences being less than reliable when storing long strings, especially those containing 0-chars, I use a different way of storing data in the app.
I use internal files (fileGetInput and fileGetOutput), I then create a HashMap<Integer, char[][]> and write it to the file using writeObject. As I have a few of those char arrays, identified by an integer ID, this way I'm saving them all in one go.
I do realise that I may be loosing something in terms of performance, however in this case reliability comes first.

Related

How to reverse string which place 2/3 of heap?

Recently I've had an interview and I was asked a strange(at least for me) question:
I should write a method which would inverse a string.
public static String myReverse(String str){
...
}
The problem is that str is a very very huge object (2/3 of memory).
I suppose only one solution:
create a new String where I will store the result, then reverse 1/2 of the source String. After using reflection, clear the second half(already reversed) of the source string underlying array and then continue to reverse.
Am I right?
Any other solutions?
If you are using reflection anyway, you could access the underlying character array of the string and reverse it in place, by traversing from both ends and swapping the chars at each end.
public static String myReverse(String str){
char[] content;
//Fill content with reflection
for (int a = 0, b = content.length - 1; a < b; a++, b--) {
char temp = content[b];
content[b] = content[a];
content[a] = temp;
}
return str;
}
I unfortunately can't think of a way that doesn't use reflection.
A String is internally a 16-bit char array. If we know the character set to be ASCII, meaning each char maps to a single byte, we can encode the string to a 8-bit byte array at only 50% of the memory cost. This fully utilizes the available memory during the transition. Then we let go of the input string to reclaim 2/3 of the memory, reverse the byte array and reconstruct the string.
public static String myReverse(String str) {
byte[] bytes = str.getBytes("ASCII");
// memory at full capacity
str = null;
// memory at 1/3 capacity
for (int i = 0; i < bytes.length / 2; i++) {
byte tmp = bytes[i];
bytes[i] = bytes[bytes.length - i - 1];
bytes[bytes.length - i - 1] = tmp;
}
return new String(bytes, "ASCII");
}
This, of course, assumes you have a little extra memory available for temporary objects created by the encoding process, array headers, etc.
It's unlikely that you can do that without using tricks like reflection or assuming that the String is stored in an efficient way (for example knowing it to be only ASCII characters). The problems in your way is that in java Strings are immutable. The other is the likely implementation of garbage collection.
The problem with the likely implementation of garbage collection is that the memory is reclaimed after the object can no longer be accessed. This means that there would be a brief period where both the input and the output of a transformation would need to occupy memory.
For example one could try to reverse the string by successively build the result and cut down the original string:
rev = rev + orig.substring(0,1);
orig = orig.substring(1);
But this relies oth that the previos incarnation of rev or orig respectively is collected as the new incarnation of rev or orig is being created so that they never occupy up to 2/3 of the memory at the same time.
To be more general one would study such a process. During the process there would be a set of objects that evolve throughout the process, both the set it self and (some of) the objects. At the start the original string would be in the set and at the end the reversed string would be there. It's clear that due to information content the total size of the objects in the set can never be lower than the original. The crucial point here is that the original string have to be deleted at some point. Before that time at most 50% of the information may exist in the other objects. So we need a construct that would at the same time delete a String object as it retains more than half of the information therein.
Such a construct would need you basically to call a method to an object returning another object an in the process remove the object as the result is being constructed. It's unlikely that the implementation would work in that way.
Your approach seem to rely on that String are indeed mutable somehow, and then there would be no problem in just reversing the string in place without having to use a lot of memory. You don't need to copy out anything there, you can do the whole thing in place: swap the [j] and then [len-1-j] (for all j<(len-1)/2)

Java char array copying yielding weird results

I wanted to optimize my code, so instead of copying my entire char array for each iteration in the alphabet, I opted to do the copying beforehand and then I'd just add chars into the copy.
E.g.:
copy "lord" (i=0)
modify the first letter (aord, bord, cord &c)
copy "lord" (i=1)
modify the second letter (lard, lbrd, lcrd &c)
&c
for (int i = 0; i < wordLength; i++) {
Word moddedWord = new Word(Arrays.copyOf(temp.word.content, wordLength));
for (int c = 0; c < alphabetLength; c++) {
if (alphabet[c] != temp.word.content[i]) {
// Word moddedWord = new Word(Arrays.copyOf(temp.word.content, wordLength));
moddedWord.content[i] = alphabet[c];
Word res = WordList.Contains(moddedWord);
if (res != null && WordList.MarkAsUsedIfUnused(res)) {
WordRec wr = new WordRec(res, temp);
q.Put(wr);
}
}
}
}
However, when I do this small change, my program doesn't work, when it used to when I instead used the commented line for copying. I've debugged this for hours on end now and I can find nothing that changes this, I've tried various forms of copying, I've tried storing the "original" word as a String and then converting it to a char array when I need to copy it, nothing seems to work. Oh by the way, "Word" is just a wrapper for char[] (Word.content is a char[] field).
You can't avoid copying if you want to store each modification of the word. Here:
new WordRec(res, temp);
you create a word record based on the mutable instance of the word and then you keep changing that one instance. You'd need to copy temp inside this constructor. So the best you achieve is copying a bit later, possibly a bit less due to the "ifology" within which it happens.
Now, if you really want to improve performance, then rework the WordList to be a WordSet and have O(1) lookup time with the Contains method.
A final note: please respect the Java naming conventions. Methods start with a lowercase letter.

Best way to modify an existing string? StringBuilder or convert to char array and back to string?

I'm learning Java and am wondering what's the best way to modify strings here (both for performance and to learn the preferred method in Java). Assume you're looping through a string and checking each character/performing some action on that index in the string.
Do I use the StringBuilder class, or convert the string into a char array, make my modifications, and then convert the char array back to a string?
Example for StringBuilder:
StringBuilder newString = new StringBuilder(oldString);
for (int i = 0; i < oldString.length() ; i++) {
newString.setCharAt(i, 'X');
}
Example for char array conversion:
char[] newStringArray = oldString.toCharArray();
for (int i = 0; i < oldString.length() ; i++) {
myNameChars[i] = 'X';
}
myString = String.valueOf(newStringArray);
What are the pros/cons to each different way?
I take it that StringBuilder is going to be more efficient since the converting to a char array makes copies of the array each time you update an index.
I say do whatever is most readable/maintainable until you you know that String "modification" is slowing you down. To me, this is the most readable:
Sting s = "foo";
s += "bar";
s += "baz";
If that's too slow, I'd use a StringBuilder. You may want to compare this to StringBuffer. If performance matters and synchronization does not, StringBuilder should be faster. If sychronization is needed, then you should use StringBuffer.
Also it's important to know that these strings are not being modified. In java, Strings are immutable.
This is all context specific. If you optimize this code and it doesn't make a noticeable difference (and this is usually the case), then you just thought longer than you had to and you probably made your code more difficult to understand. Optimize when you need to, not because you can. And before you do that, make sure the code you're optimizing is the cause of your performance issue.
What are the pros/cons to each different way. I take it that StringBuilder is going to be more efficient since the convering to a char array makes copies of the array each time you update an index.
As written, the code in your second example will create just two arrays: one when you call toCharArray(), and another when you call String.valueOf() (String stores data in a char[] array). The element manipulations you are performing should not trigger any object allocations. There are no copies being made of the array when you read or write an element.
If you are going to be doing any sort of String manipulation, the recommended practice is to use a StringBuilder. If you are writing very performance-sensitive code, and your transformation does not alter the length of the string, then it might be worthwhile to manipulate the array directly. But since you are learning Java as a new language, I am going to guess that you are not working in high frequency trading or any other environment where latency is critical. Therefore, you are probably better off using a StringBuilder.
If you are performing any transformations that might yield a string of a different length than the original, you should almost certainly use a StringBuilder; it will resize its internal buffer as necessary.
On a related note, if you are doing simple string concatenation (e.g, s = "a" + someObject + "c"), the compiler will actually transform those operations into a chain of StringBuilder.append() calls, so you are free to use whichever you find more aesthetically pleasing. I personally prefer the + operator. However, if you are building up a string across multiple statements, you should create a single StringBuilder.
For example:
public String toString() {
return "{field1 =" + this.field1 +
", field2 =" + this.field2 +
...
", field50 =" + this.field50 + "}";
}
Here, we have a single, long expression involving many concatenations. You don't need to worry about hand-optimizing this, because the compiler will use a single StringBuilder and just call append() on it repeatedly.
String s = ...;
if (someCondition) {
s += someValue;
}
s += additionalValue;
return s;
Here, you'll end up with two StringBuilders being created under the covers, but unless this is an extremely hot code path in a latency-critical application, it's really not worth fretting about. Given similar code, but with many more separate concatenations, it might be worth optimizing. Same goes if you know the strings might be very large. But don't just guess--measure! Demonstrate that there's a performance problem before you try to fix it. (Note: this is just a general rule for "micro optimizations"; there's rarely a downside to explicitly using a StringBuilder. But don't assume it will make a measurable difference: if you're concerned about it, you should actually measure.)
String s = "";
for (final Object item : items) {
s += item + "\n";
}
Here, we're performing a separate concatenation operation on each loop iteration, which means a new StringBuilder will be allocated on each pass. In this case, it's probably worth using a single StringBuilder since you may not know how large the collection will be. I would consider this an exception to the "prove there's a performance problem before optimizing rule": if the operation has the potential to explode in complexity based on input, err on the side of caution.
Which option will perform the best is not an easy question.
I did a benchmark using Caliper:
RUNTIME (NS)
array 88
builder 126
builderTillEnd 76
concat 3435
Benchmarked methods:
public static String array(String input)
{
char[] result = input.toCharArray(); // COPYING
for (int i = 0; i < input.length(); i++)
{
result[i] = 'X';
}
return String.valueOf(result); // COPYING
}
public static String builder(String input)
{
StringBuilder result = new StringBuilder(input); // COPYING
for (int i = 0; i < input.length(); i++)
{
result.setCharAt(i, 'X');
}
return result.toString(); // COPYING
}
public static StringBuilder builderTillEnd(String input)
{
StringBuilder result = new StringBuilder(input); // COPYING
for (int i = 0; i < input.length(); i++)
{
result.setCharAt(i, 'X');
}
return result;
}
public static String concat(String input)
{
String result = "";
for (int i = 0; i < input.length(); i++)
{
result += 'X'; // terrible COPYING, COPYING, COPYING... same as:
// result = new StringBuilder(result).append('X').toString();
}
return result;
}
Remarks
If we want to modify a String, we have to do at least 1 copy of that input String, because Strings in Java are immutable.
java.lang.StringBuilder extends java.lang.AbstractStringBuilder. StringBuilder.setCharAt() is inherited from AbstractStringBuilder and looks like this:
public void setCharAt(int index, char ch) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
value[index] = ch;
}
AbstractStringBuilder internally uses the simplest char array: char value[]. So, result[i] = 'X' is very similar to result.setCharAt(i, 'X'), however the second will call a polymorphic method (which probably gets inlined by JVM) and check bounds in if, so it will be a bit slower.
Conclusions
If you can operate on StringBuilder until the end (you don't need String back) - do it. It's the preferred way and also the fastest. Simply the best.
If you want String in the end and this is the bottleneck of your program, then you might consider using char array. In benchmark char array was ~25% faster than StringBuilder. Be sure to properly measure execution time of your program before and after optimization, because there is no guarantee about this 25%.
Never concatenate Strings in the loop with + or +=, unless you really know what you do. Usally it's better to use explicit StringBuilder and append().
I'd prefer to use StringBuilder class where original string is modified.
For String manipulation, I like StringUtil class. You'll need to get Apache commons dependency to use it

Java: Create an array with letter characters as index

Is it possible to create in Java an array indexed by letter characters ('a' to 'z') rather than by integers?
With such an array "a", I would like to useit in this way, for example
print (a['a']);
Is it possible to create in Java an array indexed by letter characters
('a' to 'z') rather than by integers?
Of course it is possible.
You could do this either like this:
char theChar = 'x';
print (a[theChar - 'a']);
or assuming handling only ASCII strings just declare the array of size 256. The directly index the array using your character.
char[] a = new char[256];
char theChar = 'x';
print (a[theChar]);
Now you don't care if it is uppercase/lower case or whatever.
Actually if you are interested specifically for ASCII strings using a Map could be overkill compared to a simple array. The array doesn't waste so much space and perhaps a Map (a very efficient construct) is too much for such a simple task.
Use a Map instead.
Map<Character, Object> myMap = new HashMap<Character, Object>();
myMap.put('a', something);
print(myMap.get('a'));
On the other hand, as others already suggested, you can use a char as index (but you would leave all array elements 0...'a'-1 empty):
String[] a = new String['z' + 1];
a['a'] = "Hello World";
System.out.println(a['a']);
You could create an array of 26 elements and always substract 'a' from you char index:
int[] array = new int[26];
array['a'-'a']=0;
array['b'-'a']=1;
\\ etc...
What about something simple like this?
public static int getLetterValue(char letter) {
return (int) Character.toUpperCase(letter) - 64;
}
and use it like so:
System.out.println(a[getLetterValue('a'));
This will fail pretty hard as it stand at the moment. You will need to check it's within range etc.
Alternatively you could implement the Java List interface and override the .get and .add methods so that they can use chars. But that brings me to my next point.
It's better to use a data structure that handles exceptions better, and is designed for that sort of use case. A Map is a much better choice.
Yes and no. Yes because you can do it and it will compile. Try the following code:
class foo {
public static void main(String[] args) throws Exception {
int a[] = new int[100];
a['a'] = '1';
System.out.printf("%d\n", a['a']);
}
}
No, because the chars will be implicitly converted to ints, which doesn't sound like what you're looking for.
The data structure you are looking for is called Map in Java land.
This data structure is known by various names, such as associative array in PHP; dictionary in C#, Python; hash in Ruby etc which leads to this kind of confusion.
You could do something like this:- for eg:
char[] a = new char[]{'s','t'};
int[] result = new int[256];
result[a[0]]= 100;
System.out.println(result['s']);//will print 100
No, You cannot do that. In the situation you should use Map instead.
I think this is a duplicate question! See Can Java use String as an index array key? (ex: array["a"]=1;) .
You should use a map to map the letter to the value and call get to get the value.

two dimensional array in java - difficulties

I'm used to python and django but I've recently started learning java. Since I don't have much time because of work I missed a lot of classes and I'm a bit confused now that I have to do a work.
EDIT
The program is suppose to attribute points according to the time each athlete made in bike and race. I have 4 extra tables for male and female with points and times.
I have to compare then and find the corresponding points for each time (linear interpolation).
So this was my idea to read the file, and use an arrayList
One of the things I'm having difficulties is creating a two dimensional array.
I have a file similar to this one:
12 M 23:56 62:50
36 F 59:30 20:60
Where the first number is an athlete, the second the gender and next time of different races (which needs to be converted into seconds).
Since I can't make an array mixed (int and char), I have to convert the gender to 0 and 1.
so where is what I've done so far:
public static void main(String[] args) throws FileNotFoundException {
Scanner fileTime = new Scanner (new FileReader ("time.txt"));
while (fileTime.hasNext()) {
String value = fileTime.next();
// Modify gender by o and 1, this way I'm able to convert string into integer
if (value.equals("F"))
value = "0";
else if (value.equals("M"))
value = "1";
// Verify which values has :
int index = valor.indexOf(":");
if (index != -1) {
String [] temp = value.split(":");
for (int i=0; i<temp.length; i++) {
// convert string to int
int num = Integer.parseInt(temp[i]);
// I wanted to multiply the first number by 60 to convert into seconds and add the second number to the first
num * 60; // but this way I multiplying everything
}
}
}
I'm aware that there's probably easier ways to do this but honestly I'm a bit confused, any lights are welcome.
Just because an array works well to store the data in one language does not mean it is the best way to store the data in another language.
Instead of trying to make a two dimensional array, you can make a single array (or collection) of a custom class.
public class Athlete {
private int _id;
private boolean _isMale;
private int[] _times;
//...
}
How you intend to use the data may change the way you structure the class. But this is a simple direct representation of the data line you described.
Python is a dynamically-typed language, which means you can think of each row as a tuple, or even as a list/array if you like. The Java idiom is to be stricter in typing. So, rather than having a list of list of elements, your Java program should define a class that represents a the information in each line, and then instantiate and populate objects of that class. In other words, if you want to program in idiomatic Java, this is not a two-dimensional array problem; it's a List<MyClass> problem.
Try reading the file line by line:
while (fileTime.hasNext())
Instead of hasNext use hasNextLine.
Read the next line instead of next token:
String value = fileTime.next();
// can be
String line = fileTime.nextLine();
Split the line into four parts with something as follows:
String[] parts = line.split("\\s+");
Access the parts using parts[0], parts[1], parts[2] and parts[3]. And you already know what's in what. Easily process them.

Categories