What is the shortest and most efficient way to decompose a string array into an array of int's if the string looks like:
4 1 4 2 3
5 1 4 2 -1 6
The way I have it now is to use String split method and iterate the String array into int's.. Is there a better way than this?
That's fine - I'd just call split(" ") and then use Integer.parseInt() on the resulting elements.
If you could potentially have more than one space between the ints, you'll need something like split("\\s+") for it to work properly.
If that's what you're doing, I don't think there's a better way!
EDIT: Perhaps I should qualify the term better - I mean that for all practical purposes, unless you're really hitting performance critical issues, I'd stick with this method since it's clean and easy to understand what's going on!
Using split() consumes more space [and time], as new String objects are created, but it is far more elegant [and simple] then any other way.
unless performance is very critical, I'd stick with this way.
Algorithm 3times faster than the split method! :)
Just for the fun of it I have made an algorithm that is far faster than the split method.
Maybe nothing you should use as I would say split is cleaner and cleaner is far more important than speed. Also the Donald Knuth quote of premature optimizations are the root cause of all evil.
Output
1189ms // My algorithm first loop
3305ms // Split algorithm runtime first loop
1173ms // My algorithm second loop
3305ms // Split algorithm second loop
The code
import java.util.ArrayList;
class FarmorsOptimized {
#SuppressWarnings({ "rawtypes", "unchecked" })
private static ArrayList getFarmors(String s) {
ArrayList intArr = new ArrayList();
int stopvalue = s.length() ;
for (int i = 0; i < stopvalue;) {
int negativ = 0;
if (s.charAt(i) == '-') {
negativ = 1;
}
intArr.add(Integer.parseInt(s.substring(i, i+1+negativ)));
i+=2+negativ;
}
return intArr;
}
#SuppressWarnings({ "rawtypes", "unchecked" })
private static ArrayList getSplits(String s) {
ArrayList intArr = new ArrayList();
for(String str : s.split(" ")){
intArr.add(Integer.parseInt(str));
}
return intArr;
}
public static void main(String[] args) {
String s = "1 2 4 -6 7 1 2 4 -6 7 1 2 4 -6 7 1 2 4 -6 7 1 2 4 -6 7 1 2 4 -6 7 1 2 4 -6 7";
int times = 1000000;
//Just to init everything
for (int i = 0; i < times; i++) {
getFarmors(s);
getSplits(s);
}
long starttime = System.currentTimeMillis();
for (int i = 0; i < times; i++) {
getFarmors(s);
}
System.out.println(System.currentTimeMillis() - starttime);
starttime = System.currentTimeMillis();
for (int i = 0; i < times; i++) {
getSplits(s);
}
System.out.println(System.currentTimeMillis() - starttime);
starttime = System.currentTimeMillis();
for (int i = 0; i < times; i++) {
getFarmors(s);
}
System.out.println(System.currentTimeMillis() - starttime);
starttime = System.currentTimeMillis();
for (int i = 0; i < times; i++) {
getSplits(s);
}
System.out.println(System.currentTimeMillis() - starttime);
}
Answer to comment discussion.
This answer works for all ints.
It's significantly faster than the split.
1295ms my
2193ms split
1155ms my
1889ms split
code
import java.util.ArrayList;
class FarmorsOptimized {
public static void main(String[] args) {
String s = "32324 -324 873249 -8544876 -74093 -3243274 4325 643286 92325 -21376218 -213 2132531 2314 1 2";
int times = 1000000;
long starttime = System.currentTimeMillis();
for (int i = 0; i < times; i++) {
getFarmors(s);
}
System.out.println(System.currentTimeMillis() - starttime);
starttime = System.currentTimeMillis();
for (int i = 0; i < times; i++) {
getSplits(s);
}
System.out.println(System.currentTimeMillis() - starttime);
starttime = System.currentTimeMillis();
for (int i = 0; i < times; i++) {
getFarmors(s);
}
System.out.println(System.currentTimeMillis() - starttime);
starttime = System.currentTimeMillis();
for (int i = 0; i < times; i++) {
getSplits(s);
}
System.out.println(System.currentTimeMillis() - starttime);
}
#SuppressWarnings({ "rawtypes", "unchecked" })
private static ArrayList getFarmors(String s) {
ArrayList intArr = new ArrayList();
int stopvalue = s.length();
for (int i = 0; i < stopvalue;) {
int j = 0;
while (true) {
if ((i + j) == stopvalue || s.charAt(i + j) == ' ') {
break;
}
j++;
}
intArr.add(Integer.parseInt(s.substring(i, i + j)));
i += j + 1;
}
return intArr;
}
#SuppressWarnings({ "rawtypes", "unchecked" })
private static ArrayList getSplits(String s) {
ArrayList intArr = new ArrayList();
String[] strArr = s.split(" ");
for(int i = 0; i < strArr.length ; i++){
intArr.add(Integer.parseInt(strArr[i]));
}
return intArr;
}
}
Related
I make a testing like this:
int target = 100000000;
ArrayList<Integer> arrayList = new ArrayList<>();
int[] array = new int[target];
int current;
long start, getArrayListTime, getArrayTime;
for (int i = 0; i < target; i++) {
arrayList.add(i);
array[i] = i;
}
start = System.currentTimeMillis();
for (int i = 0; i < target; i++) {
current = arrayList.get(i);
}
getArrayListTime = System.currentTimeMillis() - start;
start = System.currentTimeMillis();
for (int i = 0; i < target; i++) {
current = array[i];
}
getArrayTime = System.currentTimeMillis() - start;
System.out.println("get arrayList time: " + getArrayListTime + "ms, get array time: " + getArrayTime + "ms");
After I execute this code, the console show:
get arrayList time: 143ms, get array time: 2ms
I know that when add element to ArrayList but it have not more space to add it, it will allocate a 1.5x capacity array and copy origin array element to newest array, so it need additional time to process it.
But why I access ArrayList element, it have to spend more time than array? isn't it all both a continuous block in memory?
So, the main mistake you make in your benchmark is not taking into account the cost of Autoboxing and Unboxing.
Now to your question, let's try to build a benchmark that actually shows the difference between reading n elements from an array and from an ArrayList.
#Warmup(iterations = 3, time = 1)
#Measurement(iterations = 3, time = 1)
#BenchmarkMode(Mode.AverageTime)
#State(Scope.Thread)
#OutputTimeUnit(TimeUnit.MICROSECONDS)
public class ArrayAndListAccess {
private static final int iterations = 1_000_000;
List<Integer> arrayList = new ArrayList<>(iterations);
int[] array = new int[iterations];
#Setup
public void setup() {
for (int i = 0; i < iterations; i++) {
arrayList.add(i);
array[i] = i;
}
}
#Benchmark
public void arrayListAccess(Blackhole bh) {
for (int i = 0; i < arrayList.size(); i++) {
bh.consume(arrayList.get(i));
}
}
#Benchmark
public void arrayAccess(Blackhole bh) {
for (int i = 0; i < array.length; i++) {
bh.consume(array[i]);
}
}
public static void main(String[] args) throws Exception {
Options build = new OptionsBuilder()
.include(ArrayAndListAccess.class.getSimpleName())
.forks(2)
.addProfiler("perfasm")
.jvmArgs("-Xmx6g")
.build();
new Runner(build).run();
}
}
After running it, we get the following results:
Benchmark
Mode
Cnt
Score
Error
Units
ArrayAndListAccess.arrayAccess
avgt
6
3564.435
25.63
us/op
ArrayAndListAccess.arrayListAccess
avgt
6
4031.583
90.818
us/op
We can see that there is some difference, but not as much as in your test.
How I can improve this code,I am getting accurate output but it seems little long and unnecessary operations. Any Suggestion.
public class Test {
public static void main(String[] args) {
List<Integer> a = new ArrayList<Integer>();
a.add(1);
a.add(2);
List<Integer> b = new ArrayList<Integer>();
b.add(3);
b.add(5);
System.out.println(test(5, a, b));
}
public static long test(int n, List<Integer> a, List<Integer> b) {
// Write your code here
long retCnt = 0;
List<String> enemy = new ArrayList<String>();
for (int i = 0; i < a.size(); i++) {
enemy.add(a.get(i) + "" + b.get(i));
}
String tempstr = "";
int tempj = 1;
for (int m = 1; m <= n; m++) {
int temp = 1;
for (int i = 1; i <= n; i++) {
tempstr = "";
for (int j = tempj; j <= temp; j++) {
tempstr += j;
}
temp++;
if (!"".equalsIgnoreCase(tempstr)) {
if (isValidGroup(enemy, tempstr)) {
retCnt++;
} else {
break;
}
}
}
tempj++;
}
return retCnt;
}
public static boolean isValidGroup(List<String> enemy, String group) {
for (int i = 0; i < enemy.size(); i++) {
if (group.trim().toUpperCase().contains(String.valueOf(enemy.get(i).charAt(0)).toUpperCase())&& group.trim().contains(String.valueOf(enemy.get(i).charAt(1)).toUpperCase())) {
return false;
}
}
return true;
}
}
Short description of the problem statement.
I have a enemy list , That is contains pair such as 13 and 25 from the input array list and b respectively.
I have a number n call 5 , I have to generate possible permutations which should be not part of the enemy list.
Please comment if further clarifications needed.
Your code is slow. If n was 100, your code would require more than 100 million computations to execute.
The whole test function can however be executed in O(N) with some binomial math and if you directly jump above the indices where invalid numbers are. It can also be done in O(N^2) with the very simple algorithm below.
First thing I would do to save memory and code is to delete the variables tempj and temp, because you can use variables m and i for doing the same work and those have always the same values associated and they have to be created anyways for doing the right amount of iterations.
Also another useful thing to notice is that tempj will sometimes (in around half of all iterations to be more exact) be bigger than temp. In all those occasions, you won't be finding any valid permutations, because j iterates only from temp to tempj in increasing order. In other words, half of the computations are useless.
Tempstr can be precomputed.
Imagine tempj was 1 and temp was 3. J will then do 2 iterations from 1 to 2 and from 2 to 3. J has reached temp, so you add one to temp. Temp is now 4 and Tempj is still 1.
Now J has to do the exact previous 2 steps to get from 1 to 3, and then an additional one to get to 4, where temp is. You can skip those previous 2 steps because you already know what tempstr will look like after them. Instead of resetting j, keep increasing it as temp increases.
Here is a snippet of the O(N^2) (without taking into account isValidGroup()'s complexity, which can be easily optimized using an array of booleans, where you mark the invalid positions in N^2)
String tempstr = "";
for(int start = 1; start <= n; start++) {
tempstr = "";
for(int end = start; end <= n; end++) {
tempstr += end;
if(isValidGroup(enemy, tempstr)) {
retCnt++;
} else {
break;
}
}
}
I'm teaching a demo on Insertion Sort tomorrow. One important optimization is to add a check to the inner loop that stops it from iterating once you get an item into the right position. So basically, it's going from this:
public static void insertionSort(int[] array) {
for (int i = 0; i < array.length; i++) {
for (int j = i; j > 0; j--) {
if (array[j] < array[j-1]) {
int tmp = array[j];
array[j] = array[j-1];
array[j-1] = tmp;
}
}
}
}
to this:
public static void insertionSort(int[] array) {
for (int i = 0; i < array.length; i++) {
for (int j = i; j > 0 && array[j] < array[j-1]; j--) {
int tmp = array[j];
array[j] = array[j-1];
array[j-1] = tmp;
}
}
}
The second version should be more efficient. However, when I benchmark it, I'm actually measuring the performance of the first version as faster. I can't find the bug. Any ideas what's going on?
Here's the code I'm using to benchmark:
import java.util.Arrays;
import java.util.Random;
public class InsertionSort {
public static void main(String[] args) {
int[] stuff = getRandomArray(50000);
//System.out.println(Arrays.toString(stuff));
long started = System.currentTimeMillis();
insertionSort(stuff);
long finished = System.currentTimeMillis();
long totalTime = finished - started;
//System.out.println(Arrays.toString(stuff));
System.out.println("Started: " + started);
System.out.println("Finished: " + finished);
System.out.println("Elapsed: " + totalTime);
}
public static int[] getRandomArray(int size) {
int[] array = new int[size];
Random r = new Random();
for (int i = 0; i < array.length; i++) {
array[i] = r.nextInt(size);
}
return array;
}
public static void insertionSort(int[] array) {
// Implementation goes here
}
}
Edit: Changed the number of items in the test array, and commented out the lines to print
First of all you have written a so called microbenchmark. Your results are not meaningful because you don't have a warmup phase. This is essential to let the JVM HotSpot compiler perform its runtime optimizations.
Search for "java microbenchmark" to find some tools. An example is http://java-performance.info/jmh/
Just in case your results are meaningful I suppose that in your 2nd example the loop optimization of the HotSpot compiler is not as efficient as it is in your 1st example.
I've written a code to input the name, day and time of a few shows, with the option to have it sorted (bubble sort) by day and name. I'm using 1.4.2 (because I have to) and an ArrayList along with a simple class.
I've been staring at this for hours, left and came back to it a bunch of times, but unfortunately, it isn't working! Any idea why?! Here's my code:
//method to sort and display info
public static void sortDay(){
for(int i = 0; i < show.size() - 1; i++) {
for(int j = 0; j < show.size() - 1; j++){
showInfo current = (showInfo)show.get(j);
showInfo next = (showInfo)show.get(j+1);
if (current.day.compareTo(next.day) < 0) {
showInfo temp = new showInfo();
temp.name = ((showInfo)show.get(j)).name;
temp.day = ((showInfo)show.get(j)).day;
temp.time = ((showInfo)show.get(j)).time;
((showInfo)show.get(j)).time = ((showInfo)show.get(i)).time;
((showInfo)show.get(j)).day = ((showInfo)show.get(i)).day;
((showInfo)show.get(j)).name = ((showInfo)show.get(i)).name;
((showInfo)show.get(i)).time = temp.time;
((showInfo)show.get(i)).day = temp.day;
((showInfo)show.get(i)).name = temp.name;
}
}
}
System.out.println("Show Information");
for (int i = 0; i < show.size(); i++){
System.out.println("Name: " + ((showInfo)show.get(i)).name);
System.out.println("Day: " + ((showInfo)show.get(i)).day);
System.out.println("Time: " + ((showInfo)show.get(i)).time);
}
}
Any help would be great! Thanks in advance!
First, I'll assume you're using some kind of List - likely an ArrayList.
That said, the main operations for Bubble Sort are described as follows:
Compare for ordering
Create temporary variable
Place left value into temporary variable
Place right value into left value
Place old left value into right value from temporary value
You're shuffling about the fields, which will lead to confusion and bugs. Use the above approach instead.
Here it is illustrated with generics (so you don't have to cast anymore), and a capital class name, as is the convention. I don't have a temporary variable in this example, as I already have a reference to current.
List<ShowInfo> show = new ArrayList<>(); // assume populated
public static void sortDay(){
for(int i = 0; i < show.size(); i++) {
for(int j = 0; j < show.size() && j != i; j++) {
ShowInfo current = show.get(i);
ShowInfo next = show.get(j);
// If the current day is greater than the next day, we need to swap.
// Adjust to suit your business logic (if current is less than next).
if (current.day.compareTo(next.day) > 0) {
show.set(i, next);
show.set(j, current);
}
}
}
}
For a generic way of doing this, perhaps you could try something like:
public static <T extends Comparable> void sort(final List<T> list){
boolean remaining;
do{
remaining = false;
for(int i = 0; i < list.size()-1; i++){
final T current = list.get(i);
final T next = list.get(i+1);
if(current.compareTo(next) < 0){
list.set(i, next);
list.set(i+1, current);
remaining = true;
}
}
}while(remaining);
}
How do you fix it?
I'm just answering your question: how to fix the code you posted. For "how to improve it?" all other answers are way better than whatever I can come up with.
There are two points:
swap on the same index, in the inner for (index j)
correct swapping: where you have j write j+1 and where you have i write j
the other for is just so it will iterate enough times to get it sorted in the worst case (suggestions in other answers go for a while, much better)
That being said, the swapping pseudocode is:
if (show[j] < show[j+1]) {
temp = j+1
j+1 = j
j = temp
}
And here is the swapping code with the fixes:
if (current.day.compareTo(next.day) < 0) {
showInfo temp = new showInfo();
temp.name = ((showInfo)show.get(j+1)).name;
temp.day = ((showInfo)show.get(j+1)).day;
temp.time = ((showInfo)show.get(j+1)).time;
((showInfo)show.get(j+1)).time = ((showInfo)show.get(j)).time;
((showInfo)show.get(j+1)).day = ((showInfo)show.get(j)).day;
((showInfo)show.get(j+1)).name = ((showInfo)show.get(j)).name;
((showInfo)show.get(j)).time = temp.time;
((showInfo)show.get(j)).day = temp.day;
((showInfo)show.get(j)).name = temp.name;
}
And here is the printed result (assuming day - time - name for each show, so we are sorting on the first int):
Show Information before sort
610 - -72 - 1402
838 - -184 - 1096
-478 - 248 - 934
709 - 832 - -590
2007 - 954 - -315
Show Information after sort
2007 - 954 - -315
838 - -184 - 1096
709 - 832 - -590
610 - -72 - 1402
-478 - 248 - 934
public class myBubbleSort
{
private static int[] a;
public static void main(String[] args)
{
getArray(10);
System.out.println("Array before sorting");
printArray();
ascendingBubble();
System.out.println("Array after ascending sort");
printArray();
descendingBubble();
System.out.println("Array after descending sort");
printArray();
System.out.println();
System.out.println("Random sort");
getArray(10);
bubbleSort(true);
System.out.println("Array after Random sort");
printArray();
}
// print the number in random array
public static void printArray()
{
for (int i : a)
{
System.out.print(i + " ");
}
System.out.println();
}
// generate a random array to be sorted in ascending and descending order
public static void getArray(int size)
{
a = new int[size];
int item = 0;
for (int i = 0; i < size; i++)
{
item = (int) (Math.random() * 100);
a[i] = item;
}
}
// sort getArray in ascending order and bubblesort it
public static void ascendingBubble()
{
int temp;
System.out.println();
System.out.println("Ascending sort");
for (int i = 0; i < a.length - 1; i++)
{
for (int j = 0; j < a.length - 1; j++)
{
if (a[j] > a[j + 1])
{
temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
bubbleSort(true);
}
// sort getArray in descending order and bubblesort it
public static void descendingBubble()
{
int temp;
System.out.println();
System.out.println("Descending sort");
for (int i = 0; i < a.length - 1; i++)
{
for (int j = 0; j < a.length - 1; j++)
{
if (a[j] < a[j + 1])
{
temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
bubbleSort(true);
}
// bubble sort algorithm
public static void bubbleSort(boolean printTime)
{
boolean sorted = false;
int pass = 1;
int temp;
long startTime;
long endTime;
long duration;
startTime = System.nanoTime();
while (pass < a.length - 1 && (!sorted))
{
sorted = true;
for (int i = 0; i < a.length - 1; i++)
{
if (a[i] > a[i + 1])
{
temp = a[i];
a[i] = a[i + 1];
a[i + 1] = temp;
sorted = false;
}
}
pass = pass + 1;
}
endTime = System.nanoTime();
duration = (endTime - startTime);
if(printTime)
{
System.out.println(duration + " "+ " nano seconds");
}
}
}
currently recursion is fresh & difficult topic for me, however I need to use it in one of my algorithms.
Here is the challenge:
I need a method where I specify number of recursions (number of nested FOR loops) and number of iterations for each FOR loop. The result should show me, something simmilar to counter, however each column of counter is limited to specific number.
ArrayList<Integer> specs= new ArrayList<Integer>();
specs.add(5); //for(int i=0 to 5; i++)
specs.add(7);
specs.add(9);
specs.add(2);
specs.add(8);
specs.add(9);
public void recursion(ArrayList<Integer> specs){
//number of nested loops will be equal to: specs.size();
//each item in specs, specifies the For loop max count e.g:
//First outside loop will be: for(int i=0; i< specs.get(0); i++)
//Second loop inside will be: for(int i=0; i< specs.get(1); i++)
//...
}
The the results will be similar to outputs of this manual, nested loop:
int[] i;
i = new int[7];
for( i[6]=0; i[6]<5; i[6]++){
for( i[5]=0; i[5]<7; i[5]++){
for(i[4] =0; i[4]<9; i[4]++){
for(i[3] =0; i[3]<2; i[3]++){
for(i[2] =0; i[2]<8; i[2]++){
for(i[1] =0; i[1]<9; i[1]++){
//...
System.out.println(i[1]+" "+i[2]+" "+i[3]+" "+i[4]+" "+i[5]+" "+i[6]);
}
}
}
}
}
}
I already, killed 3 days on this, and still no results, was searching it in internet, however the examples are too different. Therefore, posting the programming question in internet first time in my life. Thank you in advance, you are free to change the code efficiency, I just need the same results.
// ...
recursion (specs, specs.size () - 1);
// ...
public void recursion(ArrayList<Integer> specs, int startWith){
for (int i = 0; i < specs.get(startWith); i++) {
// ...
if (startWith - 1 >= 0)
recursion (specs, startWith - 1);
}
}
Your function also need to now the index of the specs array to use for iteration, and also the previous numbers that should be printed:
public void recursion(ArrayList<Integer> specs, int index, String output) {
if( index >= specs.size() ) {
System.out.println(output);
return;
}
for (int i = 0; i < specs.get(index); i++ )
recursion( specs, index+1, Integer.toString(i) + " " + output );
}
The you should call it like this:
ArrayList<Integer> specs= new ArrayList<Integer>();
specs.add(5);
specs.add(7);
specs.add(9);
specs.add(2);
specs.add(8);
specs.add(9);
recursion( specs, 0, "" );
Does this snippet give the output you want? (It is compileable and executeable)
import java.util.ArrayList;
import java.util.List;
public class SO {
static ArrayList<Integer> specs = new ArrayList<Integer>();
static int[] i;
public static void main(String[] args) throws Exception {
specs.add(5); //for(int i=0 to 5; i++)
specs.add(7);
specs.add(9);
specs.add(2);
specs.add(8);
specs.add(9);
i = new int[specs.size()];
printMe(0, specs, i);
}
static void printMe(int depth, List<Integer> _specs, int[] i) {
if (_specs.isEmpty()) {
System.out.println(printI(i));
return;
} else {
for (int j = 0; j < _specs.get(0); j++) {
i[depth] = j + 1; // + 1 since you seems to want to go from 1 and not 0
printMe(depth + 1, _specs.subList(1, _specs.size()), i);
}
}
}
static String printI(int[] i) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < i.length; j++) {
sb.append(i[j]);
if (j < i.length - 1) {
sb.append(" ");
}
}
return sb.toString();
}
}
You can try this :
public static void loops(ArrayList<Integer> specs, int idx, StringBuilder res){
if(idx==specs.size()-1){
for (int i = 0; i < specs.get(idx); i++) {
System.out.println(i+" "+res);
}
}
else{
for(int i=0;i<specs.get(idx);i++){
res.insert(0,i+" ");
loops(specs,idx+1,res);
res.delete(0, 2);
}
}
}
And call with :
ArrayList<Integer> specs= new ArrayList<Integer>();
specs.add(5); //for(int i=0 to 5; i++)
specs.add(7);
specs.add(9);
specs.add(2);
specs.add(8);
specs.add(9);
loops(specs,0, new StringBuilder());