Can 2d array be converted to usable list - linq

I have a 2d array with values like this:
[0,1] = "A"
[0,2] = "A"
[0,3] = "A"
[0,4] = "A"
[0,5] = "A"
....
[1,0] = "1"
[1,1] = "2"
[1,2] = "3"
...
[2,0] = "N"
[2,1] = "N"
[2,2] = "N"
[2,3] = "N"
... So on.
Is there a way to convert this to 3 seperate lists like list1 will have all values of [0,1] [0,2]... so on. and List2 will have values of [1,0] [1,1]... so on. As i tried this:
List<string> cList = class.KVal.Cast<string>().ToList();
And this gives me a list but its not usable because i cant run operations on this as it has stored all values in one list.
I am trying following code:
var theList = Enumerable.Range(0, table.KVal.GetLength(1) - 1)
.Where(i=> table.KVal[0, i].Contains("A"))
.ToList();
And than once i get all the A values i want that to be a basic index of getting values from next 2d array like above code gets value from 0 next when it comes to 1. I want it to get exactly the same values above code got.
So i am doing this:
var index = Enumerable.Range(0, table.KVal.GetLength(1) - 1)
.Where(i=> table.KVal[0, i].Contains("A"))
.ToArray();
I am not sure though how i can implement this array to get other values.

You can always use Enumerable.Range:
var list1 = Enumerable
.Range(1, table.KVal.GetLength(1) - 1) // if you want to start at [0, 1]
.Select(i => table.KVal[0, i])
.ToList();
var list2 = Enumerable
.Range(0, table.KVal.GetLength(1)) // if you want to start at [1, 0]
.Select(i => table.KVal[1, i])
.ToList();
And so on.
Note that you can actually use this technique to traverse the array with n iterators:
var results =
from x in Enumerable.Range(0, table.KVal.GetLength(0))
from y in Enumerable.Range(0, table.KVal.GetLength(1))
select table.KVal[x, y];
This is a very simple example, but it illustrates how you can access a multidimensional array in a single Linq query.

Related

Using a pair of values as a key

Very frequently I've had the need to hash a pair of values. Often, I just generate a range between num1 and num2 and hash that as a key, but that's pretty slow because the distance between those two numbers can be quite large.
How can one go about hashing a pair of values to a table? For example, say I'm iterating through an array and want to hash every single possible pair of values into a hash table, where the key is the pair of nums and the value is their sum. What's an efficient way to do this? I've also thought about hashing an an array as the key, but that doesn't work.
Also, how would one go about extending this to 3,4, or 5 numbers?
EDIT:
I'm referring to hashing for O(1) lookup in a hashtable.
Just do it.
You can simply hash on the array...
Verification
Let me show a little experiment:
array = [ [1,2], [3,4], ["a", "b"], ["c", 5] ]
hash = {}
array.each do |e|
e2 = e.clone
e << "dummy"
e2 << "dummy"
hash[e] = (hash[e] || 0) + 1
hash[e2] = (hash[e2] || 0) + 1
puts "e == e2: #{(e==e2).inspect}, e.id = #{e.object_id}, e.hash = #{e.hash}, e2.id = #{e2.object_id}, e2.hash = #{e2.hash}"
end
puts hash.inspect
As you see, I take a few arrays, clone them, modify them separately; after this, we are sure that e and e2 are different arrays (i.e. different object IDs); but they contain the same elements. After this, the two different arrays are used as hash keys; and since they have the same content, are hashed together.
e == e2: true, e.id = 19797864, e.hash = -769884714, e2.id = 19797756, e2.hash = -769884714
e == e2: true, e.id = 19797852, e.hash = -642596098, e2.id = 19797588, e2.hash = -642596098
e == e2: true, e.id = 19797816, e.hash = 104945655, e2.id = 19797468, e2.hash = 104945655
e == e2: true, e.id = 19797792, e.hash = -804444135, e2.id = 19797348, e2.hash = -804444135
{[1, 2, "dummy"]=>2, [3, 4, "dummy"]=>2, ["a", "b", "dummy"]=>2, ["c", 5, "dummy"]=>2}
As you see, you can not only use arrays as keys, but it also recognizes them as being the "same" (and not some weird object identity which it could also be).
Caveat
Obviously this works only to a point. The contents of the arrays must recursively be well-defined with regards to hashing. I.e., you can use sane things like strings, numbers, other arrays, even nil in there.
Reference
From http://ruby-doc.org/core-2.4.0/Hash.html :
Two objects refer to the same hash key when their hash value is identical and the two objects are eql? to each other.
From http://ruby-doc.org/core-2.4.0/Array.html#method-i-eql-3F :
eql?(other) → true or false
Returns true if self and other are the same object, or are both arrays with the same content (according to Object#eql?).
hash → integer
Compute a hash-code for this array.
Two arrays with the same content will have the same hash code (and will compare using eql?).
Emphasis mine.
If you are using a range or array, then you can also call hash on it and use that.
(num1..num2).hash
[num1, num2].hash
That will return a key that you can use as a hash. I have no idea if this is efficient. It does show the source code on the range documentation and the array documentation
Another way I would do it is to turn the numbers into strings. This is the better solution if you are worried about hash collisions.
'num1:num2'
And the ruby-esque ways that I would solve your problem are:
number_array.combination(2).each { |arr| my_hash[arr.hash] = arr }
number_array.combination(2).each { |arr| my_hash[arr.join(":")] = arr }
A hash table, where the key is the pair of nums and the value is their sum:
h = {}
[1,4,6,8].combination(2){|ar| h[ar] = ar.sum}
p h #=>{[1, 4]=>5, [1, 6]=>7, [1, 8]=>9, [4, 6]=>10, [4, 8]=>12, [6, 8]=>14}
Note that using arrays as hash keys is no problem at all. To extend this to 3,4, or 5 numbers use combination(3) #or 4 or 5.

determining the sum of top-left to bottom-right diagonal values in a matrix with Ruby?

I have a square matrix of indeterminate row & column length (assume rows and columns are equal as befits a square).
I've plotted out an example matrix as follows:
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
My goal is to get a sum from top-left to bottom-right of the diagonal values.
Obviously in this example, this is all i'll need:
diagsum = matrix[0][0]+matrix[1][1]+matrix[2][2]
#=> 15
I see the pattern where it's a +1 incremental for each row & column argument in the matrix, so the code i've developed for my matrix of indeterminate length (supplied as the argument to my method diagsum would preferably need to implement some sort of row_count method on my matrix argument.
If
arr = [[1,2,3],
[4,5,6],
[7,8,9]]
then:
require 'matrix'
Matrix[*arr].trace
#=> 15
This will sum the diagonal values.
matrix = []
matrix[0] = [1,2,3]
matrix[1] = [4,5,6]
matrix[2] = [7,8,9]
def diagsum(mat)
sum = 0
mat.each_with_index { |row,i| sum += row[i] }
sum
end
puts (diagsum matrix) # 15
Not clear what x is.
But assuming that it is the number of columns/rows, you have 0..x, while the index only goes up to x - 1. You should change it to 0...x.
You are assigning to variable i, whose scope is only in the block.
You are only using i once, perhaps intended to correspond to either row or column, but not both.
You are adding the indices instead of the corresponding elements.
each will return the receiver regardless of whatever you get in the blocks.
puts will return nil regardless of whatever you get.

Fast way of checking if an element is ranked higher than another

I am writing in MATLAB a program that checks whether two elements A and B were exchanged in ranking positions.
Example
Assume the first ranking is:
list1 = [1 2 3 4]
while the second one is:
list2 = [1 2 4 3]
I want to check whether A = 3 and B = 4 have exchanged relative positions in the rankings, which in this case is true, since in the first ranking 3 comes before 4 and in the second ranking 3 comes after 4.
Procedure
In order to do this, I have written the following MATLAB code:
positionA1 = find(list1 == A);
positionB1 = find(list1 == B);
positionA2 = find(list2 == A);
positionB2 = find(list2 == B);
if (positionA1 <= positionB1 && positionA2 >= positionB2) || ...
(positionA1 >= positionB1 && positionA2 <= positionB2)
... do something
end
Unfortunately, I need to run this code a lot of times, and the find function is really slow (but needed to get the element position in the list).
I was wondering if there is a way of speeding up the procedure. I have also tried to write a MEX file that performs in C the find operation, but it did not help.
If the lists don't change within your loop, then you can determine the positions of the items ahead of time.
Assuming that your items are always integers from 1 to N:
[~, positions_1] = sort( list1 );
[~, positions_2] = sort( list2 );
This way you won't need to call find within the loop, you can just do:
positionA1 = positions_1(A);
positionB1 = positions_1(B);
positionA2 = positions_2(A);
positionB2 = positions_2(B);
If your loop is going over all possible combinations of A and B, then you can also vectorize that
Find the elements that exchanged relative ranking:
rank_diff_1 = bsxfun(#minus, positions_1, positions_1');
rank_diff_2 = bsxfun(#minus, positions_2, positions_2');
rel_rank_changed = sign(rank_diff_1) ~= sign(rank_diff_2);
[A_changed, B_changed] = find(rel_rank_changed);
Optional: Throw out half of the results, because if (3,4) is in the list, then (4,3) also will be, and maybe you don't want that:
mask = (A_changed < B_changed);
A_changed = A_changed(mask);
B_changed = B_changed(mask);
Now loop over only those elements that have exchanged relative ranking
for ii = 1:length(A_changed)
A = A_changed(ii);
B = B_changed(ii);
% Do something...
end
Instead of find try to compute something like this
Check if there is any exchanged values.
if logical(sum(abs(list1-list2)))
do something
end;
For specific values A and B:
if (list1(logical((list1-list2)-abs((list1-list2))))==A)&&(list1(logical((list1-list2)+abs((list1-list2))))==B)
do something
end;

Iterate two collection at same time

a = [1,2,3]
b = [4,5 ]
What I want is to iterate these two collection at same time and do something with iterator, the pseudo code would be like:
for i in a
for j in b
collect i * j
when one collection runs out of element, the loop stops.
the result will be [4, 10]
What I have is this:
a = [1,2,3]
b = [4,5 ]
a.zip(b).reject { |c| c.any? { |d| d.nil? } }.map { |e| e.reduce(&:*) }
Any better solution? Thanks!
And The perfect solution I am looking for is to match the intent of my pseudo code.
You can do this:
a, b = b, a if b.length < a.length
a.zip(b).map { |ia, ib| ia * ib }
# => [4, 10]
The first line makes sure that array a has at most the same number of elements as array b. This is because zip creates an array of arrays of the length of the called array. Having a as the shortest array makes sure that there would be no nils.
Here is another way to do it:
[a.length, b.length].min.times.map {|i| a[i]*b[i] }
The idea is that you take the shorter of the two array lengths, [a.length, b.length].min, and you iterate that many times over an integer, i, which you use as an index into the arrays.

How do I sort a coffeescript Map object by property value?

I have a list of articles each of which has a simple string array of Tags. I count the tag frequency like this:
Count The Tag Frquency
getTags = (articles) ->
tags= {}
for article in articles
for tag in article.Tags
tags[tag] = (tags[tag] or 0) + 1
tags
Example Result
The tags map produced is an object with property names set to the Tag name and property values set to the frequency count, like so:
Question
I would like to order this list by the property value (the frequency count), how can I achieve this?
Note: I am happy to change the counting method if required
Edit 1
Thanks to #LeonidBeschastny I now have working code:
getTags = (articles) ->
tags = {}
for article in articles
for tag in article.Tags
tags[tag] = (tags[tag] or 0) + 1
tags = do (tags) ->
keys = Object.keys(tags).sort (a, b) -> tags[b] - tags[a]
{name, count: tags[name]} for name in keys
tags
You can see that I am having to project the unsorted tags map object into a new array of sorted {name:value} objects.
This feels like it is too much work and I think maybe the original unsorted object was a mistake. Is there a way to get to the sorted array without going through this intermediate step?
Edit 2
Thanks to #hpaulj for doing some time tests and discovering that the code above is actually reasonably efficient compared to other potential solutions, such as a running sorted heap.
I have now put this code into production and it is working well.
You may sort your tags using Array::sort and then rebuild tags object:
tags = do (tags) ->
res = {}
keys = Object.keys(tags).sort (a, b) -> tags[b] - tags[a]
for k in keys
res[k] = tags[k]
res
Update
As for insertion order, mu is too short is right, it's not guaranteed by ECMA specification. V8 maintains it for literal (non-numerical) keys, but I'm not so sure about other JS engines.
So, the right solution is to use arrays anyway:
tags = do (tags) ->
keys = Object.keys(tags).sort (a, b) -> tags[b] - tags[a]
{name, count: tags[name]} for name in keys
Using a heapq. This is more complex than simply counting followed by sorting, but may be useful if we need a running sorted count.
Using the Coffeescript translation of Python heapq, https://github.com/qiao/heap.js
heap = require './heap'
# adapted from
# http://docs.python.org/2/library/heapq.html#priority-queue-implementation-notes
pq = [] # list of entries arranged in a heap
entry_finder = {} # mapping of tasks to entries
REMOVED = '<removed-task>'
counter = [0]
remove_task = (task) ->
# Mark an existing task as REMOVED. return null if not found.
entry = entry_finder[task]
if entry?
delete entry_finder[task]
entry[entry.length-1] = REMOVED
return entry
count_task = (task) ->
entry = remove_task(task)
if entry?
[priority, count, _] = entry
priority += 1
else
counter[0] += 1
count = counter[0]
priority = 1
entry = [priority, count, task]
entry_finder[task] = entry
heap.push(pq, entry)
console.log h = ['one','two','one','three','four','two','one']
for task in h
count_task(task)
console.log entry_finder
console.log pq
alist = heap.nlargest(pq, 10)
for x in alist
[priority, count, task] = x
if task != REMOVED
console.log task, priority, count
produces
[ 'one', 'two', 'one', 'three', 'four', 'two', 'one' ]
{ three: [ 1, 3, 'three' ],
four: [ 1, 4, 'four' ],
two: [ 2, 2, 'two' ],
one: [ 3, 1, 'one' ] }
[ [ 1, 1, '<removed-task>' ],
[ 1, 2, '<removed-task>' ],
[ 2, 1, '<removed-task>' ],
[ 1, 3, 'three' ],
[ 1, 4, 'four' ],
[ 2, 2, 'two' ],
[ 3, 1, 'one' ] ]
one 3 1
two 2 2
four 1 4
three 1 3

Resources