Related
From:
arr1 = np.array([ [1, 2, 3], [4, 5, 6], [7, 8, 9] ])
To:
arr1 = np.array([ [0, 1, 2, 3], [0, 4, 5, 6], [0, 7, 8, 9] ])
You can try something like this with numpy.full:
x = 0
new = np.full((arr1.shape[0], arr1.shape[1] + 1), x)
new[:, 1:] = arr1
Output
new
array([[0, 1, 2, 3],
[0, 4, 5, 6],
[0, 7, 8, 9]])
Note that you can assign any value to x.
Your (3,3) 2d array:
In [100]: arr1 = np.array([ [1, 2, 3], [4, 5, 6], [7, 8, 9] ])
In [101]: arr1
Out[101]:
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
A new (3,4) array:
In [102]: np.concatenate((np.zeros((3,1),int),arr1), axis=1)
Out[102]:
array([[0, 1, 2, 3],
[0, 4, 5, 6],
[0, 7, 8, 9]])
Any other (3,1) array (or even a (3,n)) could be added "at the start" like this.
I would like the following hash output:
{ 0 => [0,1,2], 1 => [0,1,2], 2 => [0,1,2],
3 => [3,4,5], 4 => [3,4,5], 5 => [3,4,5],
6 => [6,7,8], 7 => [6,7,8], 8 => [6,7,8]
}
Intuitively I can just hard code these values in, but I am struggle to figure out how I can dynamically assign each hash key to the appropriate array value.. For instance perhaps creating a 9.times loop?
{ 0 => (0..2).to_a, 1 => (0..2).to_a, 2 => (0..2).to_a,
3 => (3..5).to_a, 4 => (3..5).to_a, 5 => (3..5).to_a,
6 => (6..8).to_a, 7 => (6..8).to_a, 8 => (6..8).to_a
}
Thanks for any guidance
With a dynamic upper bound:
count, split = 9, 3
0.upto(count - 1).map do |i|
[i, [*(i / split * split)...(i / split) * split + split]]
end.to_h
Using modulo operations (%) you can calculate the values of the subarrays:
(0..8).map { |i| [i, (i - i%3 .. i - i%3 + 2).to_a] }.to_h
# => {0=>[0, 1, 2], 1=>[0, 1, 2], 2=>[0, 1, 2], 3=>[3, 4, 5], 4=>[3, 4, 5], 5=>[3, 4, 5], 6=>[6, 7, 8], 7=>[6, 7, 8], 8=>[6, 7, 8]}
Maybe something like this:
[0..2, 3..5, 6..8].each.with_object({}) do |range, result|
range.each do |ind|
result[ind] = range.to_a
end
end
dummy_data = {}
(0..8).to_a.each_slice(3).map{ |m| m.each{|v| dummy_data[v] = m }}
it generates expected dummy data
dummy_data
=> {0=>[0, 1, 2], 1=>[0, 1, 2], 2=>[0, 1, 2], 3=>[3, 4, 5], 4=>[3, 4, 5], 5=>[3, 4, 5], 6=>[6, 7, 8], 7=>[6, 7, 8], 8=>[6, 7, 8]}
def make_da_hash(n)
a = (0..n*n-1).to_a
a.zip(a.each_slice(n).flat_map { |e| [e]*n }).to_h
end
make_da_hash(3)
#=> {0=>[0, 1, 2], 1=>[0, 1, 2], 2=>[0, 1, 2],
# 3=>[3, 4, 5], 4=>[3, 4, 5], 5=>[3, 4, 5],
# 6=>[6, 7, 8], 7=>[6, 7, 8], 8=>[6, 7, 8]}
make_da_hash(4)
#=> {0=>[0, 1, 2, 3], 1=>[0, 1, 2, 3], 2=>[0, 1, 2, 3], 3=>[0, 1, 2, 3],
# 4=>[4, 5, 6, 7], 5=>[4, 5, 6, 7], 6=>[4, 5, 6, 7], 7=>[4, 5, 6, 7],
# 8=>[8, 9, 10, 11], 9=>[8, 9, 10, 11], 10=>[8, 9, 10, 11],
# 11=>[8, 9, 10, 11], 12=>[12, 13, 14, 15], 13=>[12, 13, 14, 15],
# 14=>[12, 13, 14, 15], 15=>[12, 13, 14, 15]}
{}.merge(*Array.new(3){|i| (0..8).group_by{|n| n / 3 * 3 + i}})
Output:
{
0=>[0, 1, 2],
3=>[3, 4, 5],
6=>[6, 7, 8],
1=>[0, 1, 2],
4=>[3, 4, 5],
7=>[6, 7, 8],
2=>[0, 1, 2],
5=>[3, 4, 5],
8=>[6, 7, 8]
}
Is there any method to split an array like this?
[1, 2, 3, 4, 5, 6, 7, 8, 9].split(3, 4, 2)
#=> [[1, 2, 3],[4, 5, 6, 7],[8, 9]]
Immutable version with λ:
▶ splitter = ->(array, *parts) do
parts.reduce([[], 0]) do |acc, i|
right = acc.last + i
[acc.first << (acc.last...right), right]
end.first.map { |r| array[r] }
end
#⇒ #<Proc:0x0055ae3d9ae7c8#(pry):18 (lambda)>
▶ splitter.((1..9).to_a, 3, 4, 2)
#⇒ [[1, 2, 3], [4, 5, 6, 7], [8, 9]]
No, there is none, but you can easily write one yourself.
class Array
def in_groups_of_n(*sizes)
sizes.map(&method(:shift))
end
end
Example:
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
arr.in_groups_of_n(3, 4, 2)
# => [[1, 2, 3], [4, 5, 6, 7], [8, 9]]
Demonstration
In case you want a none-destructive version, you can use a dup method:
class Array
def in_groups_of_n(*sizes)
duplicate = dup
sizes.map { |size| duplicate.shift(size) }
end
end
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
arr.in_groups_of_n(3,4,2)
# => [[1, 2, 3], [4, 5, 6, 7], [8, 9]
arr
# => [1, 2, 3, 4, 5, 6, 7, 8, 9]
Demonstration
Here's a naive Array implementation:
class Array
def multi_split(*sizes)
r = []
e = self.each
sizes.each do |size|
t = []
size.times do
t << e.next
end
r << t
end
r
end
end
p [1, 2, 3, 4, 5, 6, 7, 8, 9].multi_split(3, 4, 2)
# [[1, 2, 3], [4, 5, 6, 7], [8, 9]]
#Stefan mentioned it might make sense to implement it on Enumerable:
module Enumerable
def multi_split(*sizes)
Enumerator.new do |yielder|
e = self.each
sizes.each do |size|
yielder << Array.new(size){ e.next }
end
end
end
end
p [1, 2, 3, 4, 5, 6, 7, 8, 9].multi_split(3, 4, 2).to_a
# [[1, 2, 3], [4, 5, 6, 7], [8, 9]]
Another option (lossless in event the splits are not equal to the array size
def split_at(arr,splits)
rest = arr.last(arr.size - splits.reduce(:+))
enum = arr.to_enum
splits.map do |n|
n.times.map { enum.next }
end.concat(rest.empty? ? [] : [rest])
end
Then called as
split_at (1..9), [3,4,2]
#=> [[1, 2, 3], [4, 5, 6, 7], [8, 9]]
split_at (1..22), [3,4,2]
#=> [[1, 2, 3], [4, 5, 6, 7], [8, 9], [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]]
Example
class Array
def split_by_number(*sizes)
sizes.each_with_object([]) { |n,a| a << [a.empty? ? 0 : a.last.sum, n] }.
map { |start, nbr| self[start, nbr] }
end
end
[1, 2, 3, 4, 5, 6, 7, 8, 9].split_by_number 3, 4, 2
#=> [[1, 2, 3], [4, 5, 6, 7], [8, 9]]
Note that
[3, 4, 2].each_with_object([]) { |n,a| a << [a.empty? ? 0 : a.last.sum, n] }
#=> [[0, 3], [3, 4], [7, 2]]
I have created a very ugly script to collect same numbers from an array. I don't think this is a very Ruby way :) Anyone could provide a more clean solution?
ar = [5, 5, 2, 2, 2, 6, 6]
collections = []
collect_same = []
while ar.length > 0
first = ar.values_at(0).join.to_i
second = ar.values_at(1).join.to_i
if ar.length == 1
collect_same << ar[0]
collections << collect_same
break
else
sum = ar.values_at(0, 1).inject {|a,b| a + b}
if second == first
p collect_same << ar[0]
ar.shift
else
collect_same << ar[0]
collections << collect_same
collect_same = []
ar.shift
end
end
end
p collections
The output:
=> [[5, 5], [2, 2, 2], [6, 6]]
Note, that in primary array same numbers always goes one after another.
So I wouldn't have primary array like this - ar = [1, 2, 1, 2]
Using chunk_while:
[5, 5, 2, 2, 2, 6, 6].chunk_while(&:==).to_a
#=> [[5, 5], [2, 2, 2], [6, 6]]
Ruby prior to 2.3:
[5, 5, 2, 2, 2, 6, 6].each_with_object([]) do |e, acc|
acc.last && acc.last.last == e ? acc.last << e : acc << [e]
end
#=> [[5, 5], [2, 2, 2], [6, 6]]
In case if you want to do it without order:
ar.group_by(&:itself).values
=> [[5, 5], [2, 2, 2], [6, 6]]
[5, 5, 2, 2, 2, 6, 6].slice_when(&:!=).to_a
#=> [[5, 5], [2, 2, 2], [6, 6]]
One could perhaps say that Enumerable#chunk_while and Enumerable#slice_when are ying and yang.
Prior to Ruby v2.3, one might write
[5, 5, 2, 2, 2, 6, 6].chunk(&:itself).map(&:last)
and prior to v2.2,
[5, 5, 2, 2, 2, 6, 6].chunk { |n| n }.map(&:last)
just another oneliner
arr = [5, 5, 2, 2, 2, 6, 6]
arr.uniq.map {|e| [e]*arr.count(e) }
# => [[5, 5], [2, 2, 2], [6, 6]]
I have an array:
[1, 4, 4, 4, 2, 9, 0, 4, 3, 3, 3, 3, 4]
and want to replace the repeating values with a string "repeat". The repeated 4 at indices 1, 2, 3 and 3 at indices 8, 9, 10, 11 should be replaced. I should get:
[1, "repeat", 2, 9, 0, 4, "repeat", 4]
How is this accomplished?
Here are two ways you could do that.
#1 Use Enumerable#chunk:
arr = [1,4,4,4,2,9,0,4,3,3,3,3,4]
arr.chunk(&:itself).map { |f,a| a.size==1 ? f : "repeat" }
#=> [1, "repeat", 2, 9, 0, 4, "repeat", 4]
The steps:
enum = arr.chunk(&:itself)
#=> #<Enumerator: #<Enumerator::Generator:0x007febc99fb160>:each>
We can view the elements of this enumerator by converting it to an array:
enum.to_a
#=> [[1, [1]], [4, [4, 4, 4]], [2, [2]], [9, [9]], [0, [0]],
# [4, [4]], [3, [3, 3, 3, 3]], [4, [4]]]
Object#itself was added in Ruby v2.2. For earlier version you would use
enum = arr.chunk { |e| e }
It is now a simple matter to map the elements of enum as required:
enum.map { |f,a| a.size==1 ? f : "repeat" }
#=> [1, "repeat", 2, 9, 0, 4, "repeat", 4]
#2 Use Enumerable#slice_when
arr.slice_when { |e,f| e !=f }.map { |a| a.size==1 ? a.first : "repeat" }
The steps:
enum = arr.slice_when { |e,f| e !=f }
#=> #<Enumerator: #<Enumerator::Generator:0x007febc99b8cc0>:each>
a = enum.to_a
#=> [[1], [4, 4, 4], [2], [9], [0], [4], [3, 3, 3, 3], [4]]
a.map { |a| a.size==1 ? a.first : "repeat" }
#=> [1, "repeat", 2, 9, 0, 4, "repeat", 4]
slice_when was introduced in Ruby v.2.2.