java - Loop optimization on int array - java

I would like to know, which is fast way to write/read in an int array.
Here my Java code: I have three int arrays, two in read access and one int array in write access.
for(int j = h20 ; j < h21 ; j++){
for(int i = w20 ; i < w21 ; i++){
if( int_color == arr3[j*h31 + i] ) continue; //condition
arr1[(j+decY)*w11 + i+decX] = arr2[j*w21 + i];
}
}
My code is a classic 2D array loop, there are just one special condition to check.
Is it other way to write this code to decrease processing time?
Thx.

You can reduce the amount of calculations, if you separate them by variables. In your case, any calculation that relies on j alone doesn't have to be inside the inner loop because the result won't change for the rest of the loop. Instead, calculate the values outside and only use the result in the inner loop.
for(int j = h20 ; j < h21 ; j++){
int tmp1 = j*h31;
int tmp2 = (j+decY)*w11 + decX;
int tmp3 = j*w21;
// j won't change inside here, so you can simply use the precalculated values
for(int i = w20 ; i < w21 ; i++){
if( int_color == arr3[tmp1 + i] ) continue; //condition
arr1[tmp2 + i] = arr2[tmp3 + i];
}
}
Edit: If you want to reduce this even more, you could rewrite the calculation for tmp2:
(j+decY)*w11 + decX ==> j*w11 + decY*w11 + decX
Then, you could extract the decY*w11 + decX into its own variable outside the first loop.
int tmp0 = decY*w11 + decX;
for(int j = h20 ; j < h21 ; j++){
int tmp1 = j*h31;
int tmp2 = j*w11 + tmp0;
int tmp3 = j*w21;
// j won't change inside here, so you can simply use the precalculated values
for(int i = w20 ; i < w21 ; i++){
if( int_color == arr3[tmp1 + i] ) continue; //condition
arr1[tmp2 + i] = arr2[tmp3 + i];
}
}
But this will save you only one addition per iteration, so I don't think it's worth the extra effort.

Removing calculations, especially multiplications might help.
For arr3 this would be:
final int icolor = int_color;
final int ix3 = h20 + w20;
final int dx3 = h31 + h21 - h20;
for (int j = h20; j < h21; ++j) {
for (int i = w20 ; i < w21 ; ++i) {
assert ix3 == j*h31 + i;
if (icolor != arr3[ix3]) {
arr1[(j+decY)*w11 + i+decX] = arr2[j*w21 + i];
}
++ix3;
}
ix3 += dx3;
}
Whether this is really worthwile one needs to test.
Depending on the frequency of the condition, one might think of using System.arraycopy for consecutive ranges of i.

Related

CompareTo String Array - Works Explicitly, But Not Implicitly with Variables in Loop

I'm trying to compare elements in an array. When I use a variable within a loop, I get an out of bounds error. Yet when I use explicit values in place of the variables, with the same value, it works fine.
What am I missing?
The problem line is:
int result = (myList[j]).compareToIgnoreCase(myList[j + 1]);
But if I use this, it works (values should be identical):
int result = (myList[0]).compareToIgnoreCase(myList[1]);
Have searched high and dry for this. Other posters had different issues. Would appreciate any input! Here's the example with dummy content:
public class methodSortTest
{
public static void main(String[] args)
{
// Create and load data into array
String[] myList = new String[2];
myList[0] = "Charlie";
myList[1] = "Bravo";
// Compare, positive/negative
for (int j = 0; j < myList.length; j++)
{
int result = (myList[j]).compareToIgnoreCase(myList[j + 1]);
System.out.println("Result is: " + result);
}
}
}
Try this:
change this:
for (int j = 0; j < myList.length; j++)
to this:
for (int j = 0; j < myList.length-1; j++)
problem is inside this statement:
int result = (myList[j]).compareToIgnoreCase(myList[j + 1]);
because you are accessing the j+1
Simple Helping material:
https://www.geeksforgeeks.org/understanding-array-indexoutofbounds-exception-in-java/
When j equals 1, myList[j + 1] evaluates to myList[2] which throws an ArrayIndexOutOfBoundsException. There is no item at index 2 because you have only inserted items at index 0 and 1.
Reference: https://docs.oracle.com/javase/7/docs/api/java/lang/ArrayIndexOutOfBoundsException.html
Change your for loop from
for (int j = 0; j < myList.length; j++)
To
for (int j = 0; j < myList.length-1; j++) // note the "-1"

Fill array within nested loops

I am trying to fill an array in two nested loops however for each second pPiece[] i want to give it a k attribute of 0 or 1 every second pPiece[] respectively
For example -
pPieces[0] = new Piece(0,pcName,1);
pPieces[1] = new Piece(1,pcName,1);
pPieces[2] = new Piece(0,pcName,1);
pPieces[3] = new Piece(1,pcName,1);
etc....
What i have
private Piece pPieces[] = new Piece[8];
for(int j=0; j<pCount; j++) //pCount = 4
{
for(int k=0; k<pcCount; k++) //pcCount = 2
{
String pcName = "Piece " + (allocation());
pPieces[j+k] = new Piece(k,pcName,1);
}
}
Doing it this way results in pPieces[] index being over written 4 times, i think. Is it possible to properly fill this array which should have 8 objects stored in it with every second 'k' equaling 0 or 1 respectively?
The issue in your current solution is that j+k will get the same value multiple times during the two loops:
for(int j=0; j<pCount; j++) //pCount = 4
{
for(int k=0; k<pcCount; k++) //pcCount = 2
{
String pcName = "Piece " + (allocation());
pPieces[j+k] = new Piece(k,pcName,1);
}
}
For example, when j = 0 and k = 1, you will have j + k = 1. But you will also have that when j = 1 and k = 0.
The problem comes from the fact that you're incrementing the variable j by steps of 1 when you should increment it by steps of pcCount; and the related issue is that j should go to pCount*pcCount and not pCount only.
for(int j=0; j<pCount*pcCount; j+=pcCount) //<--- j+=pcCount here, not j++
{
for(int k=0; k<pcCount; k++)
{
String pcName = "Piece " + allocation();
pPieces[j+k] = new Piece(k,pcName,1);
}
}
As a side-note, consider using more descriptive variable names instead of pCount and pcCount.
Refactor your code as follows, The issues is pPieces[j+k] = new Piece(k,pcName,1);
Your j+k => 0,1,1,2,2,3,3,4
Corrected Code
private Piece pPieces[] = new Piece[8];
int count=0;
for(int j=0; j<pCount; j++) //pCount = 4
{
for(int k=0; k<pcCount; k++) //pcCount = 2
{
String pcName = "Piece " + (allocation());
pPieces[count++] = new Piece(k,pcName,1);
}
}
Indeed, j+k will be overlapping. But 2j+k does not.
You need to replace by :
private Piece pPieces[] = new Piece[8];
for(int j=0; j<pCount; j++) //pCount = 4
{
for(int k=0; k<pcCount; k++) //pcCount = 2
{
String pcName = "Piece " + (allocation());
pPieces[2*j+k] = new Piece(k,pcName,1);
}
}
}
The % operator can be of use here:
private Piece pPieces[] = new Piece[8];
for(int j = 0; j < pPieces.length; j++) {
String pcName = "Piece " + (allocation());
pPieces[j] = new Piece(j % 2,pcName,1);
}
The % (modulus) operator returns the remainder of integer division.
e.g.
0 % 2 = 0
1 % 2 = 1
2 % 2 = 0
3 % 2 = 1
Creating an alternation of 1 and 0.

Stopping a for loop without using break

I'm trying to write a program that prints all substrings of entered string. For example if user enter "rum" the output will be this:
r
u
m
ru
um
rum
import java.util.Scanner;
public class AllSubStrings
{
public static void main(String[]args)
{
Scanner in = new Scanner(System.in);
System.out.print("Enter a string: ");
String str = in.next();
String sub = "";
for(int i=0; i<str.length(); i++)
{
for(int a=0; a<str.length() ; a++)
{
if(i+a+1>str.length())break;
sub = str.substring(a,i+a+1);
System.out.println(sub);
}
}
}
}
This program works perfectly but since we didn't learn how to use "break" in classes, i'm looking for something different. Any idea apart from "break" are welcome.
Thanks in advance.
You can use this while loop cycle instead of for:
int a = 0;
while (a < str.length && i + a < str.length()) {
sub = str.substring(a, i + a + 1);
System.out.println(sub);
a++;
}
Also it is possible to replace break with return statement
Calculate how many possible substrings there can be for a certain length. For example, length 1 = 1 substring, length 2 = 3, length 3 = 6, and so on.
Then loop for that many times. There should be a generic formula you can use for no matter how long of an input string.
You don't need a break to do this task.
int len = str.length();
for (int i = 0; i < len; i++) {
for (int j = i; j < len; j++) {
System.out.println( str.substring( i, j + 1 ) );
}
}
You can have two conditions in the for loop
for(int a = 0; a < str.length() && i + a < str.length(); a++)
{
sub = str.substring(a,i+a+1);
System.out.println(sub);
}
Note that i + a + 1 <= str.length() is the same as i + a < str.length()

How to use two variables in a for loop?

for (int i = 0; i < ary1.length; i++) {
int j = 1;
System.out.println("Enter integer #"+ j++ +":" );
ary1[i] = elementValue.nextInt();
}
This is part of code that allows me to input values into an array. I want the system out to display enter integer #1 for element 0 and integer #2 for element 1 and so on. Variable j isn't increasing although I set it to raise by one each time. Any guidance would be greatly appreciated. Thank you
You do not really need the second counter. You can do the following.
for (int i = 0; i < ary1.length; i++) {
System.out.println("Enter integer #"+ (i+1) +":" );
ary1[i] = elementValue.nextInt();
}
Simply move the declaration of j outside of the loop:
int j = 1;
for (int i = 0; i < ary1.length; i++) {
System.out.println("Enter integer #"+ j++ +":" );
ary1[i] = elementValue.nextInt();
}
You need to declear the j var outside the loop. In you code the j var is assigning every time. So increment is interrupting. It should be
int j = 1;
for (int i = 0; i < ary1.length; i++) {
System.out.println("Enter integer #"+ j++ +":" );
ary1[i] = elementValue.nextInt();
}
While a second variable is not needed here (and it is a bit silly because of the relationship), it is perfectly valid to "loop multiple variables", including declaring and incrementing them together:
for (int i = 0, j = 1; i < ary1.length; i++, j++) {
// ..
}
Note that j is also scope to the loop (albeit with an initial value of 1), and is also incremented in the loop independently of (but at the same time as) i.

Creating word pairs, triplets etc for evaluation in Bleu

I need to create a list of word pairs, triplets etc for evaluation in the Bleu metric. Bleu starts with unigrams (a single word) and goes up to N-grams - the N being specified at runtime.
For example, given the sentence
"Israeli officials are responsible for airport security"
For unigrams it would just be a list of the words. For bigrams it would be
Israeli officials
officials are
are responsible
responsible for
for airport
airport security
The relevant trigrams are
Israeli officials are
officials are responsible
are responsible for
responsible for aiport
for airport security
I've coded a working Bleu that hard codes the NGrams to 4 and brute forces the calculations of the unigrams etc. It's ugly as hell, and besides, I need to be able to supply the N at run time.
The snippet that's trying to generate the pairs / triplets etc -
String current = "";
int temp = 0;
for (int i = 0; i < goldWords.length - N_GRAM_ORDER; i++) {
current = current + ":" + goldWords[i];
while (temp < N_GRAM_ORDER) {
current = current + ":" + goldWords[temp + i];
temp++;
}
goldNGrams.add(current);
current = "";
temp = 0;
}
}
Edit - so the output from this snippet should be for bigrams -
israeli:officials
officials:are
are:responsible
responsible:for
for:airport
airport:security
Where goldWords is a String array containing the individual words to be made into NGrams.
I've been tinkering with this loop for days, drawing out the relationships etc and it just won't click for me. Can anyone see what I'm doing wrong?
I would change this:
String current = "";
int temp = 0;
for (int i = 0; i < goldWords.length - N_GRAM_ORDER; i++) {
current = current + ":" + goldWords[i];
while (temp < N_GRAM_ORDER) {
current = current + ":" + goldWords[temp + i];
temp++;
}
goldNGrams.add(current);
current = "";
temp = 0;
}
}
to this:
String current = "";
for (int i = 0; i < goldWords.length(); i++){
for (int j = 0; j < N_GRAM_ORDER; j++){
if (i + j < goldWords.length())
current += ":" + goldWords[i + j];
}
goldNGrams.add(current);
current = "";
}
So, the outer for loop iterates through the first word to be included, the inner loop iterates through all the words to be included. One thing to note is that the if statement is used to prevent an array out of bounds error. This should be moved to outside the inner for loop if you only want complete n-grams.
With the if statement where it is you will get:
Israeli:officials
officials:are
are:responsible
responsible:for
for:airport
airport:security
security
If you want:
Israeli:officials
officials:are
are:responsible
responsible:for
for:airport
airport:security
instead, try this code:
String current = "";
for (int i = 0; i < goldWords.length(); i++){
if (i + N_GRAM_ORDER < goldWords.length()){
for (int j = 0; j < N_GRAM_ORDER; j++){
current += ":" + goldWords[i + j];
}
}
goldNGrams.add(current);
current = "";
}
(the above code is done without checking it against the compiler, so there might be an Off By One or minor syntax error in it. Validate it, but it will get you close).
Here's an alternative that uses a String[] to collect the ngrams instead of a string. I changed the number of iterations on the outer for loop to ensure it captures the last n-gram.
public static List<String[]> ngrams(String[] gold, int n_length) {
List<String[]> list = new ArrayList<String[]>();
for (int i = 0; i < gold.length - (n_length-1); i++) {
String[] ngram = new String[n_length];
for(int j = 0; j < n_length; j++) {
ngram[j] = gold[i+j];
}
list.add(ngram);
}
return list;
}
according to the N_GRAM programming output
int N_GRAM_ORDER = 3, temp = 0, i;
for (i = 0; i <= goldWords.length - N_GRAM_ORDER; i += N_GRAM_ORDER) {
while (temp < N_GRAM_ORDER) {
current = current + ":" + goldWords[temp + i];
temp++;
}
goldGrams.add(current);
current = "";
temp = 0;
}
if ((temp + i) < goldWords.length) {
temp += i;
while (temp < goldWords.length) {
current = current + ":" + goldWords[temp++];
}
goldGrams.add(current);
}
}
output
Israeli:officials:are
responsible:for:airport
security

Categories