Getting every two elements from an array in CoffeeScript - coffeescript

I want to use every pair of entries in an array. Is there an effective way to do this in CoffeeScript without using the length property of the array?
I am currently doing something like the following:
# arr is an array
for i in [0...arr.length]
first = arr[i]
second = arr[++i]

CoffeeScript has for ... by for adjusting the step size of a normal for loop. So iterate over the array in steps of 2 and grab your elements using an index:
a = [ 1, 2, 3, 4 ]
for e, i in a by 2
first = a[i]
second = a[i + 1]
# Do interesting things here
Demo: http://jsfiddle.net/ambiguous/pvXdA/
If you want, you could use a destructured assignment combined with an array slice inside the loop:
a = [ 'a', 'b', 'c', 'd' ]
for e, i in a by 2
[first, second] = a[i .. i + 1]
#...
Demo: http://jsfiddle.net/ambiguous/DaMdV/
You could also skip the ignored variable and use a range loop:
# three dots, not two
for i in [0 ... a.length] by 2
[first, second] = a[i .. i + 1]
#...
Demo: http://jsfiddle.net/ambiguous/U4AC5/
That compiles to a for(i = 0; i < a.length; i += 2) loop like all the rest do so the range doesn't cost you anything.​

Related

Coffeescript - How to get for loop to loop over newly added elements in an array?

I need to loop over an array and add more elements to that array if needed. But coffeescript seems to terminate the loop at old length (where the array ended when the for loop started). I need the loop to loop over newly added elements. How do I fix this?
arr = [1,2,3,4,5]
for x in arr
console.log(x + ">>>" + arr)
if(x < 3)
arr.push(5)
Output on console:
JSFiddle
This doesnt seem to be a problem in js:
arr = [1,2,3,4,5]
for(i=0 ; i<arr.length ; i++){
console.log(arr[i]);
if(arr[i] < 3)
arr.push(5)
}
Output on console:
JSFiddle
Do not mutate the array you're iterating over. Split your algorithm to multiple segments, e.g.:
arr = [1,2,3,4,5]
to_add = []
# 1. Check for new items to add
for x in arr
if x < 3
to_add.push(5)
# 2. Add the new items
arr = arr.concat(to_add)
# 3. Iterate over the array, including the new items
for x in arr
your_thing(x)

Find substring in cell array of numbers and strings

I have a cell array consisting of numbers, strings, and empty arrays. I want to find the position (linear or indexed) of all cells containing a string in which a certain substring of interest appears.
mixedCellArray = {
'adpo' 2134 []
0 [] 'daesad'
'xxxxx' 'dp' 'dpdpd'
}
If the substring of interest is 'dp', then I should get the indices for three cells.
The only solutions I can find work when the cell array contains only strings:
http://www.mathworks.com/matlabcentral/answers/2015-find-index-of-cells-containing-my-string
http://www.mathworks.com/matlabcentral/newsreader/view_thread/255090
One work-around is to find all cells not containing strings, and fill them with '', as hinted by this posting. Unfortunately, my approach requires a variation of that solution, probably something like cellfun('ischar',mixedCellArray). This causes the error:
Error using cellfun
Unknown option.
Thanks for any suggestions on how to figure out the error.
I've posted this to usenet
EDUCATIONAL AFTERNOTE: For those who don't have Matlab at home, and end up bouncing back and forth between Matlab and Octave. I asked above why cellfun doesn't accept 'ischar' as its first argument. The answer turns out to be that the argument must be a function handle in Matlab, so you really need to pass #ischar. There are some functions whose names can be passed as strings, for backward compatibility, but ischar is not one of them.
How about this one-liner:
>> mixedCellArray = {'adpo' 2134 []; 0 [] 'daesad'; 'xxxxx' 'dp' 'dpdpd'};
>> index = cellfun(#(c) ischar(c) && ~isempty(strfind(c, 'dp')), mixedCellArray)
index =
3×3 logical array
1 0 0
0 0 0
0 1 1
You could get by without the ischar(c) && ..., but you will likely want to keep it there since strfind will implicitly convert any numeric values/arrays into their equivalent ASCII characters to do the comparison. That means you could get false positives, as in this example:
>> C = {65, 'A'; 'BAD' [66 65 68]} % Note there's a vector in there
C =
2×2 cell array
[ 65] 'A'
'BAD' [1×3 double]
>> index = cellfun(#(c) ~isempty(strfind(c, 'A')), C) % Removed ischar(c) &&
index =
2×2 logical array
1 1 % They all match!
1 1
Just use a loop, testing with ischar and contains (added in R2016b). The various *funs are basically loops and, in general, do not offer any performance advantage over the explicit loop.
mixedCellArray = {'adpo' 2134 []; 0 [] 'daesad'; 'xxxxx' 'dp' 'dpdpd'};
querystr = 'dp';
test = false(size(mixedCellArray));
for ii = 1:numel(mixedCellArray)
if ischar(mixedCellArray{ii})
test(ii) = contains(mixedCellArray{ii}, querystr);
end
end
Which returns:
test =
3×3 logical array
1 0 0
0 0 0
0 1 1
Edit:
If you don't have a MATLAB version with contains you can substitute a regex:
test(ii) = ~isempty(regexp(mixedCellArray{ii}, querystr, 'once'));
z=cellfun(#(x)strfind(x,'dp'),mixedCellArray,'un',0);
idx=cellfun(#(x)x>0,z,'un',0);
find(~cellfun(#isempty,idx))
Here is a solution from the usenet link in my original post:
>> mixedCellArray = {
'adpo' 2134 []
0 [] 'daesad'
'xxxxx' 'dp' 'dpdpd'
}
mixedCellArray =
'adpo' [2134] []
[ 0] [] 'daesad'
'xxxxx' 'dp' 'dpdpd'
>> ~cellfun( #isempty , ...
cellfun( #(x)strfind(x,'dp') , ...
mixedCellArray , ...
'uniform',0) ...
)
ans =
1 0 0
0 0 0
0 1 1
The inner cellfun is able to apply strfind to even numerical cells because, I presume, Matlab treats numerical arrays and strings the same way. A string is just an array of numbers representing the character codes. The outer cellfun identifies all cells for which the inner cellfun found a match, and the prefix tilde turns that into all cells for which there was NO match.
Thanks to dpb.

Add a new element to the beginning of an existing cell array

I want to add an element into an existing 20x1 cell array so that the array becomes 21x1. I found a way to do add elements at the end from an answer to a previous question in the group
Q{end+1} = 'E1';
But how to do this at the beginning?
Luckily, concatenation works with cell arrays too:
First, let's create a dummy cell array A to use as example:
A = {1;2;'ABC';#(n)sin(n)}
A =
[ 1]
[ 2]
'ABC'
#(n)sin(n)
Now, let's concatenate it with 'E1' using brackets:
A = ['E1'; A]
A =
'E1'
[ 1]
[ 2]
'ABC'
#(n)sin(n)
The more explicit alternative is vertcat (vertical concatenation):
A = vertcat('E1', A)
A =
'E1'
[ 1]
[ 2]
'ABC'
#(n)sin(n)

How can I filter my array of numbers in Matlab/Octave?

I have a very trivial example where I'm trying to filter by matching a String:
A = [0:1:999];
B = A(int2str(A) == '999');
This
A(A > 990);
works
This
int2str(5) == '5'
also works
I just can't figure out why I cannot put the two together. I get an error about nonconformant arguments.
int2str(A) produces a very long char array (of size 1 x 4996) containing the string representations of all those numbers (including spacing) appended together end to end.
int2str(A) == '999'
So, in the statement above, you're trying to compare a matrix of size 1 x 4996 with another of size 1 x 3. This, of course, fails as the two either need to be of the same size, or at least one needs to be a scalar, in which case scalar expansion rules apply.
A(A > 990);
The above works because of logical indexing rules, the result will be the elements from the indices of A for which that condition holds true.
int2str(5) == '5'
This only works because the result of the int2str call is a 1 x 1 matrix ('5') and you're comparing it to another matrix of the same size. Try int2str(555) == '55' and it'll fail with the same error as above.
I'm not sure what result you expected from the original statements, but maybe you're looking for this:
A = [0:1:999];
B = int2str(A(A == 999)) % outputs '999'
I am not sure that the int2str() conversion is what you are looking for. (Also, why do you need to convert numbers to strings and then carry out a char comparison?)
Suppose you have a simpler case:
A = 1:3;
strA = int2str(A)
strA =
1 2 3
Note that this is a 1x7 char array. Thus, comparing it against a scalar char:
strA == '2'
ans =
0 0 0 1 0 0 0
Now, you might wanna transpose A and carry out the comparison:
int2str(A')=='2'
ans =
0
1
0
however, this approach will not work if the number of digits of each number is not the same because lower numbers will be padded with spaces (try creating A = 1:10 and comparing against '2').
Then, create a cell array of string without whitespaces and use strcmp():
csA = arrayfun(#int2str,A','un',0)
csA =
'1'
'2'
'3'
strcmp('2',csA)
Should be much faster, and correct to turn the string into a number, than the other way around. Try
B = A(A == str2double ('999'));

How to check if an element in a cell array is unique or repeated

I have a <465x1> cell array. For check each element, I want to check whether it is unique or a repeated element.
Use unique for this purpose, it can work on cell arrays too:
[U, ic, iu] = unique(C);
Where C is your cell array. U is a new cell array with the same values as C but without repetitions. You can then count the occurrences of each value using histc:
[U, ic, iu] = unique(C);
count = histc(iu, 1:numel(ic))
Example
For the sake of the example, let's generate a random cell array of strings first:
strings = {'foo'; 'bar'; 'baz'; 'bang'};
C = strings(ceil(numel(strings) * rand(6, 1)))
This should generate something like this:
C =
'bang'
'baz'
'foo'
'bang'
'bar'
'foo'
Now we count the occurrences of each value in C:
C = strings(ceil(numel(strings) * rand(6, 1)));
[U, ic, iu] = unique(C);
count = histc(iu, 1:numel(ic))
This should result in:
U =
'foo'
'bar'
'baz'
'bang'
count =
2
1
1
2
which means that 'foo' and 'bang' are repeated twice, while the rest only once, which is correct.If you are only interested in the truly unique values, you can do:
U(count == 1)
Which should return in our example:
'bar'
'baz'
Note that each element in count represents the corresponding value in U (not strings, they may have a different order).