Scala: Shift elements in an Array - arrays

I'm getting used to the various data structures in Scala and I've noticed that this function (contrived example), which is supposed to move every character in the mutable array to the right by one, has no effect on the array:
def shiftRight(str: String): Array[Char] = {
val chars = str.toCharArray
for(i <- chars.length - 1 until 0) chars(i) = chars(i - 1)
chars
}
println(shiftRight("ABCD").mkString)
which produces the result
ABCD
not the expected
AABC

Default step for range is one. See class Range here and implicit that gets you to it here.
Instead of
for(i <- chars.length - 1 until 0)...
you need:
for(i <- chars.length - 1 until 0 by -1)...

Related

Scala: filtering an array with filter vs. for each

I have this problem: I want to iterate on the elements of an array that satisfy a certain condition.
The first thing I though is to use the filter method on the original array and then iterates over the resulting elements. But I had some memory usage problem with that, i.e. java heap space.
When a filter is applied on an array, it will instantiate a new array? So it will copy each element?
Is it better to use this approach:
array.filter(<condition>).foreach{ element =>
do something
}
Or the following one?
for(i <- array.indices if <condition>){
do something
}
Moreover, I wrote these two tests:
With for
val size = 10000000
val elements = Array.ofDim[Double](size)
for (i <- elements.indices) {
elements.update(i, math.random)
}
var cont = 0
val n = 0.5
while(true){
cont = 0
for (j <- elements.indices if elements(j) < n) {
cont += 1
}
println(cont)
}
with filter
val size = 10000000
val elements = Array.ofDim[Double](size)
for (i <- elements.indices) {
elements.update(i, math.random)
}
val n = 0.5
while(true){
val valid = elements.filter(x => x < n)
println(valid.size)
}
and I checked the memory usage with VisualVM, it seem that the first solution uses less memory than the second one.
This is the memory used by the first solution
This is the memory used by the second solution
The for expression use the withFilter method rather than filter, which avoids creating the intermediate Array. So either use the for version or use withFilter rather than filter.

How to create an array of squared values of another array

I need to make a method square_array that takes in one argument which is going to be an array. This method needs to loop through the original array and multiply each element with itself then insert the squared value into the new array.
I'm getting an error when doing this array[i] ** 2 = output[i] I think it's because of the equals sign but I'm not sure.
def square_array(array)
i = 0
array = ('1'..'3').to_a
output = []
while i < array.length do
array[i] ** 2 = output[i]
i += 1
end
end
I expect
square_array([1,2,3])
to return
[1,4,9]
When trying to declare a variable or assign a new value to it, it should be on the left side of the equals operator. So if you have a which is 5 and you want to assign the value of a multiplied by 2 to a new variable b you would do:
b = a * 2
and not
a * 2 = b
That's why array[i] ** 2 = output[i] isn't producing the result you expect it to produce.
Looking at your method, a few other things are a bit off:
def square_array(array)
i = 0
array = ('1'..'3').to_a
output = []
while i < array.length do
array[i] ** 2 = output[i]
i += 1
end
end
You accept the array variable as an input, then you overwrite it by doing array = ('1'..'3').to_a (no need to use the single quotes ' when declaring numbers (Integers)) and lose the input value. Usually you'd declare the array outside the method and then pass the value to the method. Something like this:
array = (1..3).to_a
def square_array(array)
i = 0
output = []
while i < array.length do
output[i] = array[i] ** 2 #like explained in the first part
i += 1
end
end
But the method still doesn't return anything, so simply adding output as the last line in the method should solve the problem (remember, Ruby returns the last line of the method even without the return statement).
So something like this:
def square_array(array)
i = 0
output = []
while i < array.length do
output[i] = array[i] ** 2
i += 1
end
output
end
I should also add, there's an easier way to write this method, using the #map function (like #pjs said) for example:
def square_array(array)
array.map{|x| x**2}
end
You can then call the method by doing
square_array(array)
Here, your assignment is mistake,
array[i] ** 2 = output[i]
It should be
output[i] = array[i] ** 2

Code is not executing the else condition in the inner most loop when matching array to array index by index?

var amazon = activeSpreadsheet.getSheetByName('Amazon');
var lastRow1 = amazon.getLastRow();
var array1 = amazon.getRange('A2:A' + lastRow1).getValues();
var source = activeSpreadsheet.getSheetByName('ProductDetails');
var lastRow2 = source.getLastRow();
var array2 = source.getRange('B2:B' + lastRow2).getValues();
n = 2;
x = 0; // match
z = 0; // non-match
for (var i = 0; i < array2.length; i++){
for (var j = 0; j < array1.length; j++){
if (array2[i] !== array1[j]){
z = z + 1;
}
else {
x = 9999
}
}
newsheet.getRange([n],[5]).setValue(z);
newsheet.getRange([n],[6]).setValue(x);
if (z > x) {
newsheet.getRange([n],[1]).setValue(array2[i]);
n == n++;
z = 0;
x = 0;
}
else if (z < x) {
z = 0;
x = 0;
}
}
My project is written in GAS (google app scripts) which is essentially, for all intents and purposes JS with variation in libraries.
Basically I am grabbing an element in the array2 and passing it through a loop to match to array1. For every time it does not match it adds 1, and when it matches (should only match once if it has any matches) it stores an arbitrary large number (larger than length of array1) and compares them.
As you can see I've written out to display these values and I always get z = 5183 (length of array1) and x = 0 (meaning no non-matches found). Therefore even if something exists in array 2 and 1 it will always write it to the cell.
What should happen is if there is a match, z= 5182 and x= 9999 (or arbitrary large number) and since 5182 < 9999 it doesn't do anything.
Is my scope wrong? Or am I not writing the If/Else correctly? Or is it something else?
Your code performs a strict comparison between the elements of two Arrays. That's fine, in general. However, for those specific Arrays those elements are also Arrays, which means strict (in)equality is checking to see if those are the exact same array object in memory. See this question for more information.
You probably wanted to do a value-based comparison, which means you need to compare the specific element of that inner array (i.e., index again). if (array2[i][0] !== array1[j][0]) {...} will check the 1st element of the inner array.
Looking at the instantiation of array1 and array2, we see that these are indeed 2D arrays from a single-column Ranges, so there will be only 1 element in each inner array. You can reduce the level of indexing necessary by flattening these arrays when you read them:
const array1 = sheet.getRange(...).getValues().map(function (row) { return row[0]; });
const array2 = ...;
I'm also not sure why you are passing in arrays to Sheet#getRange - you should pass in 1-4 arguments in manners consistent with the method signatures detailed in the Apps Script documentation.
Note that there are much better algorithms for checking if a value exists in a given array - you re-scan all of the 2nd array for every value of the first array. You should conduct thorough research into this topic before asking a new question on how to improve your algorithm.
Lastly, you should implement the best practice of using batch methods - you currently call setValue in a loop. Consider storing the results to write in an array, and then writing with Range#setValues once your loop has completed. There are many questions available for you to review on this topic.

What is the simplest way to access array (not vector) element from middle to outermost?

I want to create a game, which monster is aligned from left to right horizontally, the order of monsters has other logical meaning (e.g.: the appearing sequence), but I want to play some effects which starts from the middle monster
the array, for example, for odd number size array:
int[] a=new int[]{1,2,3,4,5};
the access sequence is 3,2,4,1,5 (or 3,4,2,5,1)
for even number size array:
int[] a=new int[]{1,2,3,4,5,6};
the access sequence is 3,4,2,5,1,6 or (4,3,5,2,6,1)
If it is in something like vector in c++, it will be:
std::vector<int> a;
a.push_back(1);
a.push_back(2);
a.push_back(3);
a.push_back(4);
a.push_back(5);
while(a.size()>0){
printf("%d\n",a[a.size()/2]);
a.erase(a.begin()+a.size()/2);
}
which the output is
3
4
2
5
1
But I want an algorithm which is suitable to be used in array, which the position of element cannot be changed,
I tried something like:
int a[]={1,2,3,4,5};
for(int i=a.size()/2;i>=0 && i<a.size();i=XXXX){
printf("%d\n",a[i]);
}
which XXXX is the update statement, which I still don't know what should it be.
In fact, I don't know if my init value and condition statement in for loop is correct. I even don't know if it can be done by a single loop.
Ok, I know I can have a temp vector and then copy the index to do that, but I also want to know if it can be done in a single for loop without any temp vector or array.
Can anyone help (or is there another simple algorithm to do that?)?
This is an answer for the edited question that is language-agnostic and wants a single function to display the elements in the stated order.
First, chose a "middle" index.
var i = Math.floor((a.length-1)/2);
Then alternate right and left moving outwards incrementally until either edge of the array is encountered.
To facilitate this, start with a variable d = 0 which will be the distance from the middle element. This d will be updated like so upon each iteration
d += -(2*d) + (d > 0 ? 0 : 1);
with the below update pattern:
0, 1, -1, 2, -2, ...
If the middle index is 2 in array [1,2,3,4,5], then applying a[i + d] will result in
3, 4, 2, 5, 1
I hope this is what you are looking for.
Here is a JavaScript implementation:
var a = [1,2,3,4,5,7,8];
var i = Math.floor((a.length-1)/2);
for (var d = 0; i+d >= 0 && i+d < a.length;) {
// Print out the value
console.log(a[i + d]);
// Outward-moving logic
d += -(2*d) + (d > 0 ? 0 : 1);
}
or if you want this all in the for-loop like you've tried in your question, you can do this:
var a = [1,2,3,4,5,7,8];
var i = Math.floor((a.length-1)/2);
for (var d = 0; i+d >= 0 && i+d < a.length; d += -(2*d) + (d > 0 ? 0 : 1)) {
console.log( a[i + d] ); // print the value
}
Result on [1,2,3,4,5] (odd-length array):
3 4 2 5 1
Result on [1,2,3,4,5,6,7,8] (even-length array):
4 5 3 6 2 7 1 8
Demo: JSBin
An algorithm to list the elements from innermost to outermost is to pull off the last and first entries (pop and shift) in the array in alternation until no elements are left, then reverse the list of what you have pulled off. This works for odd and even-length arrays naturally.
For example,
1,2,3,4,5,6
1,2,3,4,5 6
2,3,4,5 6,1
2,3,4 6,1,5
3,4 6,1,5,2
3 6,1,5,2,4
6,1,5,2,4,3
3,4,2,5,1,6 // Reversed list from above
and
1,2,3,4,5
1,2,3,4 5
2,3,4 5,1
2,3 5,1,4
3 5,1,4,2
5,1,4,2,3
3,2,4,1,5 // Reversed list from above
You can use this above algorithm to create an index map array which you can use to access your main array in the order you requested. For example:
// Start with an array of indices
// from 0..arr.length-1
0,1,2,3,4
0,1,2,3 4
1,2,3 4,0
1,2 4,0,3
2 4,0,3,1
4,0,3,1,2
2,1,3,0,4 // Reversed list from above
Then you have a mapping array
int[] arr = new int[]{1,2,3,4,5};
int[] map = new int[]{2,1,3,0,4};
which you can use to access your main array, for example
arr[map[0]]; // returns 3
Edit: Added Java implementation and demo.
public static int[] creatIndexMap(int length) {
// Create a deque so elements can be removed from both ends
Deque<Integer> tmp = new LinkedList<Integer>();
for(int i = 0; i < length; i++) {
tmp.add(i);
}
// In alternation remove the last and first entries of tmp
// and add them in reverse order to the map array
int[] map = new int[length];
int index = length-1;
while (!tmp.isEmpty()) {
// Remove last element
map[index--] = (int) tmp.removeLast();
// Remove first element
if(!tmp.isEmpty()) {
map[index--] = (int) tmp.removeFirst();
}
}
return map;
}
Demo: IDEOne

How to fill an empty character array?

I'm trying decode an array of 1's and 0's using variable length coding. For example, if the string is [1 0 1 1], and A = [1 0] and B = [1 1], my program should give me a string something like: ['A', 'B'].
I first created an empty character array x = repmat(char(0),1,10)
But now when I detect a code word using a for loop and if statements, how do I add the character to this array x? Would it display the characters in the decoded string?
First of all, pre-defining the length of x is unnecessary in MATLAB because the language allows you resize arrays on-the-fly. That being said, preallocation is a sometimes a good idea because it will run faster.
Assuming you want to preallocate the length of x, you can assign a character to an element in x directly:
% Preallocate x
x = repmat(char(0),1,10);
% Assign a character to x
x(1) = 'A';
Where you can replace the 1 with any element in the array.
The challenge with this is that you need to keep track of where you are at in this preallocated array. If you already wrote characters to positions 1, 2, and 3, you need to know that the next assignment will write to the 4th element of x: x(4) = ....
A more elegant solution might be the following:
x = [];
if foundLetter
x(end) = 'A';
end
This adds the letter A to the end of the pre-defined character array x. It doesn't require that you preallocate the length of x.
You can index the character array x just as you would an array of doubles.
x(1) = 'A'; %Assign the char 'A' to the first element of x
.
.
.
x(10) = 'B'; %Assign the char 'B' to the tenth element of x
Here is a short example of what you would like to do.
clear decodedMsg
% define a dictionary between codes and corresponding characters
code{1,1} = 'A'; code{1,2} = '11';
code{2,1} = 'B'; code{2,2} = '101';
code{3,1} = 'C'; code{3,2} = '100';
% declare a sample message, corresponds to ABCBA
msg = [1 1 1 0 1 1 0 0 1 0 1 1 1];
%keeps track of the number of matches found, used to add to decodedMsg
counter = 1;
% get length of message and use to iterate through the msg
N = length(msg);
buffer = []; %must declare buffer if you are to use (end + 1) indexing later on
for i = 1:N
buffer(end + 1) = msg(i); %add the next msg value to the buffer
strBuf = strrep(num2str(buffer),' ',''); %convert buffer into string, e.x. [1 0 1] => '101'
findMatch = ismember(code(:,2),strBuf); %findMatch contains a 1 if a match is found
if any(findMatch) %if any element in findMatch is 1
decodedMsg(counter) = code{findMatch,1};%use that element to index a char in code cell array
counter = counter + 1; %increment counter since another code was found
buffer = []; %reset buffer for next string of 1s and 0s
end
end

Resources