Related
I have a list structured like follows:
s = [
[
[[0, 1, 1], [0, 0, 0]],
[[0, 0, 1], [0, 1, 0]],
[[0, 0, 0], [0, 1, 1]],
[[1, 0, 0], [0, 0, 0]],
[[0, 0, 0], [1, 0, 0]],
[[1, 0, 0], [0, 0, 0]],
],
[
[[1, 0, 0], [0, 0, 0]],
[[0, 0, 0], [1, 0, 0]],
[[0, 1, 1], [0, 0, 0]],
[[0, 0, 1], [0, 1, 0]],
[[0, 1, 0], [0, 0, 1]],
[[0, 0, 0], [0, 1, 1]]
],
# And so on
]
For each element at the first index, s[0], if the second sub-array, s[0][i][1], matches a corresponding first element in s[1], then we have a path, or a part of a path. It's complicated so I'll give an example:
s = [
[
[[0, 1, 1], *[0, 0, 0]*], <---- This goes to multiple possibilities
[[0, 0, 1], [0, 1, 0]],
[[0, 0, 0], [0, 1, 1]],
[[1, 0, 0], [0, 0, 0]],
[[0, 0, 0], [1, 0, 0]],
[[1, 0, 0], [0, 0, 0]],
],
[
[[1, 0, 0], [0, 0, 0]],
[*[0, 0, 0]*, [1, 0, 0]], <- here
[[0, 1, 1], [0, 0, 0]],
[[0, 0, 1], [0, 1, 0]],
[[0, 1, 0], [0, 0, 1]],
[*[0, 0, 0]*, [0, 1, 1]] <- and here
],
# And so on
]
How can I find the amount of paths for each given element?
I have an array of arrays as given below.
[
["Horse", 8, 0, 0, 0],
["Horse", 0, 0, 12, 0],
["Horse", 0, 7, 0, 0],
["Dog", 1, 0, 0, 0],
["Dog", 0, 0, 3, 0],
["Dog", 0, 3, 0, 0],
["Test", 5, 0, 0, 0],
["Test", 0, 0, 2, 0],
["Test", 0, 0, 0, 2],
["Cat", 5, 0, 0, 0],
["Cat", 0, 0, 4, 0],
["Cat", 0, 2, 0, 0]
]
I want to merge the different arrays who start with the same first elements together and replacing the 0 by the value who are at the same position inside the other array, like the result below.
[
["Horse", 8, 7, 12, 0],
["Dog", 1, 3, 3, 0],
["Test", 5, 0, 2, 2],
["Cat", 5, 2, 4, 0]
]
So far I have this function:
array.each_with_index do |line, idx|
if array[idx+1].present? && line[0] == array[idx+1][0]
line.each_with_index do |l, i|
if l != 0 && array[idx+1][i] == 0
array[idx+1][i] = array[idx][i]
end
end
end
end
But it is not completely what I'm trying to do, but i'm close. Does anyone have some insights?
Not certain what the question is, but assuming that the array given is arr, you can get the result by:
arr
.group_by(&:first)
.map{|k, v| [k, *v.transpose.drop(1).map{|a| a.inject(:+)}]}
or as pointed out by Cary Swoveland:
arr
.group_by(&:first)
.map{|k, v| [k, *v.transpose.drop(1).map(&:sum)]}
Result:
[
["Horse", 8, 7, 12, 0],
["Dog", 1, 3, 3, 0],
["Test", 5, 0, 2, 2],
["Cat", 5, 2, 4, 0]
]
Assuming your initial array of arrays is stored in arr:
arr.each_with_object(Hash.new { |h, k| h[k] = [0] * 4 }) do |(name, *vals), acc|
(0...vals.size).each { |i| acc[name][i] += vals[i] }
end.map { |k, v| [k, *v] }
#⇒ [["Horse", 8, 7, 12, 0],
# ["Dog", 1, 3, 3, 0],
# ["Test", 5, 0, 2, 2],
# ["Cat", 5, 2, 4, 0]]
The key to the solution is to maintain a hash and convert it to the array in the very end. The hash is easier to lookup and operate in general.
The accumulator uses the default values to simplify adding new values to.
arr = [["Horse", 8, 0, 0, 0], ["Horse", 0, 0, 12, 0], ["Horse", 0, 7, 0, 0],
["Dog", 1, 0, 0, 0], ["Dog", 0, 0, 3, 0], ["Dog", 0, 3, 0, 0],
["Test", 5, 0, 0, 0], ["Test", 0, 0, 2, 0], ["Test", 0, 0, 0, 2],
["Cat", 5, 0, 0, 0], ["Cat", 0, 0, 4, 0], ["Cat", 0, 2, 0, 0]]
require 'matrix'
arr.each_with_object({}) do |(k,*arr),h|
h[k] = h.key?(k) ? (h[k] + Vector[*arr]) : Vector[*arr]
end.map { |a,v| [a, *v.to_a] }
#=> [["Horse", 8, 7, 12, 0],
# ["Dog", 1, 3, 3, 0],
# ["Test", 5, 0, 2, 2],
# ["Cat", 5, 2, 4, 0]]
Requiring 'matrix' loads the class Vector as well as Matrix. See Vector::[], Vector#+ and Vector#to_a.
This does not require the elements of arr be ordered in any way.
with this you won't have limit after the name of animal ["Dog", 1, 4, 5, 0, 6, 3, ...]
array.group_by { |obj| obj[0] }.map do |key, values|
rest = values.reduce([]) do |memo, value|
value[1..-1].each_with_index do |item, i|
memo[i] ||= 0
memo[i] = [item, memo[i]].max
end
memo
end
[key] + rest
end
Following is simple one,
hash = array.group_by(&:first)
hash.map { |k,v| v.map { |x| x[1..-1] }.transpose.map {|x| x.reduce(:+)}.unshift(k) }
I have the following Daru Data Frame with a categorical variable called search_term:
home,search_term,bought
0,php,1
0,java,1
1,php,1
...
I want to convert it to a Daru Data Frame with binary columns, something like:
home,php,java,bought
0,1,0,1
0,0,1,1
1,1,0,1
...
I can't find a way to achieve it. I know it's possible in Python's Panda but I want to use Ruby with the Darus gem.
Thanks.
According to a blog post written by Yoshoku, the author of Rumale machine learning library, you can do it like:
train_df['IsFemale'] = train_df['Sex'].map { |v| v == 'female' ? 1 : 0 }
Rumale's label encoder is also useful for the categorical variable.
require 'rumale'
encoder = Rumale::Preprocessing::LabelEncoder.new
labels = Numo::Int32[1, 8, 8, 15, 0]
encoded_labels = encoder.fit_transform(labels)
# Numo::Int32#shape=[5]
# [1, 2, 2, 3, 0]
Rumale::Preprocessing::OneHotEncoder
encoder = Rumale::Preprocessing::OneHotEncoder.new
labels = Numo::Int32[0, 0, 2, 3, 2, 1]
one_hot_vectors = encoder.fit_transform(labels)
# > pp one_hot_vectors
# Numo::DFloat#shape[6, 4]
# [[1, 0, 0, 0],
# [1, 0, 0, 0],
# [0, 0, 1, 0],
# [0, 0, 0, 1],
# [0, 0, 1, 0],
# [0, 1, 0, 0]]
But, conversion of Daru::Vector and Numo::NArray needs to use to_a.
encoder = Rumale::Preprocessing::LabelEncoder.new
train_df['Embarked'] = encoder.fit_transform(train_df['Embarked'].to_a).to_a
I am trying to edit an algorithm found here.
I want the adjacency matrix to be loaded from file (formatting of the file doesn't matter to me, it can be either like this [0,1,1,0] or just 0110) with G = file.read().split("\n")
However, I get an error no implicit conversion of Fixnum into String (TypeError)
And I already know I need to convert this string to ints, but how to do it properly to not lose the formatting required by this DFS method?
I guess it's pretty easy, but I'm a begginer in Ruby (and graphs :v) and can't get it to work...
Edit:
So the code I'm using to read from file to an array of arrays is:
def read_array(file_path)
File.foreach(file_path).with_object([]) do |line, result|
result << line.split.map(&:to_i)
end
end
And the result I get from a file (for example)
01101010
01010101
01010110
10101011
01011111
is this:
=> [[[1101010], [1010101], [1010110], [10101011], [1011111]]]
What I need, however, is:
=> [[[1,1,0,1,0,1,0], [1,0,1,0,1,0,1], [1,0,1,0,1,1,0], [1,0,1,0,1,0,1,1], [1,0,1,1,1,1,1]]]
So that it would work with the algorithm mentioned in the first line of my post (I'll copy it here, if it takes too much place I can delete it and leave link only):
G = [0,1,1,0,0,1,1], # A
[1,0,0,0,0,0,0],
[1,0,0,0,0,0,0],
[0,0,0,0,1,1,0],
[0,0,0,1,0,1,1],
[1,0,0,1,1,0,0],
[1,0,0,0,1,0,0] # G
LABLES = %w(A B C D E F G)
def dfs(vertex)
print "#{LABLES[vertex]} " # visited
edge = 0
while edge < G.size
G[vertex][edge] = 0
edge += 1
end
edge = 0
while edge < G.size
if ( G[edge][vertex] != 0 && edge != vertex)
dfs(edge)
end
edge += 1
end
end
dfs(0)
split's default separator is a whitespace. To make it split every char you need to explicitly say it:
'01101101'.split.map(&:to_i)
# => [ 1101101 ]
'01101101'.split('').map(&:to_i)
# => [ 0, 1, 1, 0, 1, 1, 0, 1 ]
you can also use chars to do the same job:
'01101101'.chars.map(&:to_i)
# => [ 0, 1, 1, 0, 1, 1, 0, 1 ]
I don't know how your read_array is used, but it can be simplified to:
def read_array(file_path)
File.foreach(file_path).map do |line|
line.chomp.chars.map(&:to_i)
end
end
read_array('my_file.txt')
# => [[1, 1, 0, 1, 0, 1, 0], [1, 0, 1, 0, 1, 0, 1], [1, 0, 1, 0, 1, 1, 0], [1, 0, 1, 0, 1, 0, 1, 1], [1, 0, 1, 1, 1, 1, 1]]
If you still get the extra [, you can either take only the first item:
my_array[0]
Or (if there is more than one item the uber-array) - use flat_map:
uber_array = [[[1, 0, 1, 0, 1, 0, 1], [1, 0, 1, 0, 1, 1, 0], [1, 0, 1, 0, 1, 0, 1, 1]],
[[1, 0, 1, 0, 1, 0, 1, 1], [1, 0, 1, 1, 1, 1, 1]]]
uber_array.flat_map { |a| a }
# => [[1, 0, 1, 0, 1, 0, 1], [1, 0, 1, 0, 1, 1, 0], [1, 0, 1, 0, 1, 0, 1, 1], [1, 0, 1, 0, 1, 0, 1, 1], [1, 0, 1, 1, 1, 1, 1]]
Code works, but feels very brute force, suggestions?
Goal of the code is to supply an array length, and then as fast as possible generate all possible unique binary combinations with that array length.
CODE:
class Array
def sequence(i = 0, *a)
return [a] if i == size
self[i].map {|x|
sequence(i+1, *(a + [x]))
}.inject([]) {|m, x| m + x}
end
end
[(0..1),(0..1),(0..1)].sequence
OUTPUTS:
[[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]
permutation and repeated_permutation are built in, so you can do:
def sequence(n)
[0, 1].repeated_permutation(n).to_a
end
p sequence(3) #=>[[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]
"All unique binary combinations" with n bits is nothing but (0...2**n), so the only task is to efficiently convert from an integer to its binary representation, and the following is a solution that does not rely on string generation/manipulation:
def sequence(n)
ret = []
(2**n).times do |number|
ret << []
(n - 1).downto(0) do |bit|
ret.last << number[bit]
end
end
ret
end
sequence(3)
# => [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]
Or, if you prefer a version more oriented on list operations, this is pretty much the same:
def sequence(n)
(0...2**n).map {|number|
(1..n).map {|bit|
number[n-bit]
}
}
end