Multiplying within 2D array - arrays

I'm trying to get the product of a permutation of an array:
orig_arr = (89..99).to_a
perm = [[89, 90], [89, 91], [89, 92], [89, 93]...]
need = [[8010], [8099], [8188]...]
My best guess was to enumerate, but reduce doesn't function within each:
perm.each{|set| set.reduce(:*)}
Why doesn't this work? And, is it better to not create a 2D array, and go with a hash or matrix to solve this problem?

You can make it work by using Array#map instead of each:
orig_arr = (89..99).to_a
orig_arr.permutation(2).map { |set| [set.reduce(:*)] }
# => [[8010], [8099], [8188], [8277], [8366], [8455], . . . ]]

Related

get output of numpy loadtxt as a single array rather than multiple array

I have a CSV file:
8.84,17.22,13.22,3.84
3.99,11.73,19.66,1.27
Def jo(x):
data=np.loadtxt(x,delimiter=',')
Return data
Print(jo('data.csv')
The code returns:
[ [8.84 17.22 13.22 3.84]
[3.99 11.73 19.66 1.27] ]
But I want all these elements in a single array, because I want to find their mean and median.
How to combine these 2 arrays into 1 ?
use numpy.rehshape
# data: data is your array
>>> data.reshape(-1)
In [245]: txt="""8.84,17.22,13.22,3.84
...: 3.99,11.73,19.66,1.27"""
In [246]: data = np.loadtxt(txt.splitlines(), delimiter=',')
In [247]: data
Out[247]:
array([[ 8.84, 17.22, 13.22, 3.84],
[ 3.99, 11.73, 19.66, 1.27]])
In [248]: data.shape
Out[248]: (2, 4)
That is one array, just 2d.
There are various ways of turning that into a 1d array:
In [259]: arr = data.ravel()
In [260]: arr
Out[260]: array([ 8.84, 17.22, 13.22, 3.84, 3.99, 11.73, 19.66, 1.27])
But there's no need to do that. mean (and median) without axis parameter acts on the raveled array. Check the docs:
In [261]: np.mean(data)
Out[261]: 9.971250000000001
In [262]: np.mean(arr)
Out[262]: 9.971250000000001

Find the index by current sort order of an array in ruby

If there is an array
array A = ["a","b","c","d"] #Index is [0,1,2,3]
And it's sorted to.
array A = ["d","c","b","a"]
I need an array that returns me the updated index based on the sorted order
[3,2,1,0]
I'm trying to find a solution to this ruby
UPDATE to the question
If a is sorted to
array A = ["d","b","c","a"] #not a pure reverse
Then the returned index array should be
[3,1,2,0]
You need to create a mapping table that preserves the original order, then use that order to un-map the re-ordered version:
orig = %w[ a b c d ]
orig_order = orig.each_with_index.to_h
revised = %w[ d c b a ]
revised.map { |e| orig_order[e] }
# => [3, 2, 1, 0]
So long as your elements are unique this will be able to track any shift in order.
Here is one way to do this:
original_array = ["a","b","c","d"]
jumbled_array = original_array.shuffle
jumbled_array.map {|i| original_array.index(i)}
#=> [1, 3, 0, 2]
Note:
In this sample, output will change for every run as we are using shuffle to demonstrate the solution.
The solution will work only as long as array has no duplicate values.
If you do wish to solution to work with arrays with duplicate values, then, one possibility is to look at object_id of array members while figuring out the index.
jumbled_array.map {|i| original_array.map(&:object_id).index(i.object_id)}
This solution will work as long as jumbled_array contains element from original_array and no elements were recreated using dup or something that results in change in object_id values
You can use the map and index methods.
arr = ["a","b","c","d"]
sort_arr = ["d","c","b","a"]
sort_arr.map{|s| arr.index(s)}
# => [3, 2, 1, 0]

How to build a new Ruby array from a Hash keys

I want to build a new array starting from a hash with the following format:
HashConst = {[120,240] => 60, [240,480]=> 30} #Constant
I need to build a new array and assign as value to a new constant with the following format:
[ [[120,240] ,1], [[240,480], 1] ]
I tried :
NewArrayConst = HashConst.keys.each{ |res| [res, 1]}
but I get instead
[ [120,240], [240,480] ]
Only solution I found is the following:
tempVar = []
HashConst.keys.each_with_index{ |res,idx| tempVar [idx] = [res, 1]}
NewArrayConst = tempVar
Anyone knows a better solution to this and can explain why I cannot get the output I expect from NewArrayConst = HashConst.keys.each{ |res| [res, 1]}. I'm using 2.2.2-p95
Edit:
As many pointed out Hash var name is wrong and misleading, I have updated that to avoid confusion
You need to use map instead of each.
Array#each method does not return the result of the code executed in the block, but instead just returns the array on which each was called, which in your case is the value of hash.keys.
Array#map collects the values returned by block into an array.
hash = {[120,240] => 60, [240,480]=> 30}
p array = hash.keys.map{ |res| [res, 1]}
#=> [[[120, 240], 1], [[240, 480], 1]]
NOTE: Do not name your variable Hash as it is already a well-known class in Ruby. Use lower case hash if need be. Also, avoid camel case for variable names such as NewArrayConst, as Ruby recommends use of snake_case for naming variables - you can refer Ruby Style Guide for more details.
h = {[120,240] => 60, [240,480]=> 30}
val = 1
h.keys.product([val])
#=> [[[120, 240], 1], [[240, 480], 1]]
Have you tried Hash.to_a? Sometimes things are easier than you think.

How to generate multiple arrays containing elements from another array?

Using just Ruby I am trying to
Generate an array of random numbers
Create a new 2 dimensional array containing x amount of arrays filled with x amount of samples from the original number list.
This is what I have...
a = 1000.times.map{rand(100)}.to_a
b = 5.times.map{a.sample}
#=> [3, 96, 23, 45, 41]
I basically want to be able to generate what I did in b, x amount of times.
Is this possible?
Thank you for the comments everyone!
Just wrap your definition of b in another map:
a = 1000.times.map{rand(100)} # to_a is unnecessary here, map returns an array
b = 5.times.map{5.times.map{a.sample}}
A one-liner to do what you want.
3.times.map {2.times.map {rand 1000} }
#=> [[267, 476], [109, 950], [345, 137]]
I don't have Rails installed at the moment, so here's a pure Ruby solution.
a = (0..1000).to_a.map! { rand(100) }
x = 2
b = (0..x).to_a.map! { a.sample(x) }
# [[83, 73], [55, 93], [57, 18]]

Convert an array into an index hash in Ruby

I have an array, and I want to make a hash so I can quickly ask "is X in the array?".
In perl, there is an easy (and fast) way to do this:
my #array = qw( 1 2 3 );
my %hash;
#hash{#array} = undef;
This generates a hash that looks like:
{
1 => undef,
2 => undef,
3 => undef,
}
The best I've come up with in Ruby is:
array = [1, 2, 3]
hash = Hash[array.map {|x| [x, nil]}]
which gives:
{1=>nil, 2=>nil, 3=>nil}
Is there a better Ruby way?
EDIT 1
No, Array.include? is not a good idea. Its slow. It does a query in O(n) instead of O(1). My example array had three elements for brevity; assume the actual one has a million elements. Let's do a little benchmarking:
#!/usr/bin/ruby -w
require 'benchmark'
array = (1..1_000_000).to_a
hash = Hash[array.map {|x| [x, nil]}]
Benchmark.bm(15) do |x|
x.report("Array.include?") { 1000.times { array.include?(500_000) } }
x.report("Hash.include?") { 1000.times { hash.include?(500_000) } }
end
Produces:
user system total real
Array.include? 46.190000 0.160000 46.350000 ( 46.593477)
Hash.include? 0.000000 0.000000 0.000000 ( 0.000523)
If all you need the hash for is membership, consider using a Set:
Set
Set implements a collection of unordered values with no
duplicates. This is a hybrid of Array's intuitive inter-operation
facilities and Hash's fast lookup.
Set is easy to use with Enumerable objects (implementing
each). Most of the initializer methods and binary operators accept
generic Enumerable objects besides sets and arrays. An
Enumerable object can be converted to Set using the
to_set method.
Set uses Hash as storage, so you must note the following points:
Equality of elements is determined according to Object#eql? and Object#hash.
Set assumes that the identity of each element does not change while it is stored. Modifying an element of a set will render the set to an
unreliable state.
When a string is to be stored, a frozen copy of the string is stored instead unless the original string is already frozen.
Comparison
The comparison operators <, >, <= and >= are implemented as
shorthand for the {proper_,}{subset?,superset?} methods. However, the
<=> operator is intentionally left out because not every pair of
sets is comparable. ({x,y} vs. {x,z} for example)
Example
require 'set'
s1 = Set.new [1, 2] # -> #<Set: {1, 2}>
s2 = [1, 2].to_set # -> #<Set: {1, 2}>
s1 == s2 # -> true
s1.add("foo") # -> #<Set: {1, 2, "foo"}>
s1.merge([2, 6]) # -> #<Set: {1, 2, "foo", 6}>
s1.subset? s2 # -> false
s2.subset? s1 # -> true
[...]
Public Class Methods
new(enum = nil)
Creates a new set containing the elements of the given enumerable
object.
If a block is given, the elements of enum are preprocessed by the
given block.
try this one:
a=[1,2,3]
Hash[a.zip]
You can do this very handy trick:
Hash[*[1, 2, 3, 4].map {|k| [k, nil]}.flatten]
=> {1=>nil, 2=>nil, 3=>nil, 4=>nil}
If you want to quickly ask "is X in the array?" you should use Array#include?.
Edit (in response to addition in OP):
If you want speedy look up times, use a Set. Having a Hash that points to all nils is silly. Conversion is an easy process too with Array#to_set.
require 'benchmark'
require 'set'
array = (1..1_000_000).to_a
set = array.to_set
Benchmark.bm(15) do |x|
x.report("Array.include?") { 1000.times { array.include?(500_000) } }
x.report("Set.include?") { 1000.times { set.include?(500_000) } }
end
Results on my machine:
user system total real
Array.include? 36.200000 0.140000 36.340000 ( 36.740605)
Set.include? 0.000000 0.000000 0.000000 ( 0.000515)
You should consider just using a set to begin with, instead of an array so that a conversion is never necessary.
I'm fairly certain that there isn't a one-shot clever way to construct this hash. My inclination would be to just be explicit and state what I'm doing:
hash = {}
array.each{|x| hash[x] = nil}
It doesn't look particularly elegant, but it's clear, and does the job.
FWIW, your original suggestion (under Ruby 1.8.6 at least) doesn't seem to work. I get an "ArgumentError: odd number of arguments for Hash" error. Hash.[] expects a literal, even-lengthed list of values:
Hash[a, 1, b, 2] # => {a => 1, b => 2}
so I tried changing your code to:
hash = Hash[*array.map {|x| [x, nil]}.flatten]
but the performance is dire:
#!/usr/bin/ruby -w
require 'benchmark'
array = (1..100_000).to_a
Benchmark.bm(15) do |x|
x.report("assignment loop") {hash = {}; array.each{|e| hash[e] = nil}}
x.report("hash constructor") {hash = Hash[*array.map {|e| [e, nil]}.flatten]}
end
gives
user system total real
assignment loop 0.440000 0.200000 0.640000 ( 0.657287)
hash constructor 4.440000 0.250000 4.690000 ( 4.758663)
Unless I'm missing something here, a simple assignment loop seems the clearest and most efficient way to construct this hash.
Rampion beat me to it. Set might be the answer.
You can do:
require 'set'
set = array.to_set
set.include?(x)
Your way of creating the hash looks good. I had a muck around in irb and this is another way
>> [1,2,3,4].inject(Hash.new) { |h,i| {i => nil}.merge(h) }
=> {1=>nil, 2=>nil, 3=>nil, 4=>nil}
I think chrismear's point on using assignment over creation is great. To make the whole thing a little more Ruby-esque, though, I might suggest assigning something other than nil to each element:
hash = {}
array.each { |x| hash[x] = 1 } # or true or something else "truthy"
...
if hash[376] # instead of if hash.has_key?(376)
...
end
The problem with assigning to nil is that you have to use has_key? instead of [], since [] give you nil (your marker value) if the Hash doesn't have the specified key. You could get around this by using a different default value, but why go through the extra work?
# much less elegant than above:
hash = Hash.new(42)
array.each { |x| hash[x] = nil }
...
unless hash[376]
...
end
Maybe I am misunderstanding the goal here; If you wanted to know if X was in the array, why not do array.include?("X") ?
Doing some benchmarking on the suggestions so far gives that chrismear and Gaius's assignment-based hash creation is slightly faster than my map method (and assigning nil is slightly faster than assigning true). mtyaka and rampion's Set suggestion is about 35% slower to create.
As far as lookups, hash.include?(x) is a very tiny amount faster than hash[x]; both are twice as a fast as set.include?(x).
user system total real
chrismear 6.050000 0.850000 6.900000 ( 6.959355)
derobert 6.010000 1.060000 7.070000 ( 7.113237)
Gaius 6.210000 0.810000 7.020000 ( 7.049815)
mtyaka 8.750000 1.190000 9.940000 ( 9.967548)
rampion 8.700000 1.210000 9.910000 ( 9.962281)
user system total real
times 10.880000 0.000000 10.880000 ( 10.921315)
set 93.030000 17.490000 110.520000 (110.817044)
hash-i 45.820000 8.040000 53.860000 ( 53.981141)
hash-e 47.070000 8.280000 55.350000 ( 55.487760)
Benchmarking code is:
#!/usr/bin/ruby -w
require 'benchmark'
require 'set'
array = (1..5_000_000).to_a
Benchmark.bmbm(10) do |bm|
bm.report('chrismear') { hash = {}; array.each{|x| hash[x] = nil} }
bm.report('derobert') { hash = Hash[array.map {|x| [x, nil]}] }
bm.report('Gaius') { hash = {}; array.each{|x| hash[x] = true} }
bm.report('mtyaka') { set = array.to_set }
bm.report('rampion') { set = Set.new(array) }
end
hash = Hash[array.map {|x| [x, true]}]
set = array.to_set
array = nil
GC.start
GC.disable
Benchmark.bmbm(10) do |bm|
bm.report('times') { 100_000_000.times { } }
bm.report('set') { 100_000_000.times { set.include?(500_000) } }
bm.report('hash-i') { 100_000_000.times { hash.include?(500_000) } }
bm.report('hash-e') { 100_000_000.times { hash[500_000] } }
end
GC.enable
If you're not bothered what the hash values are
irb(main):031:0> a=(1..1_000_000).to_a ; a.length
=> 1000000
irb(main):032:0> h=Hash[a.zip a] ; h.keys.length
=> 1000000
Takes a second or so on my desktop.
If you're looking for an equivalent of this Perl code:
grep {$_ eq $element} #array
You can just use the simple Ruby code:
array.include?(element)
Here's a neat way to cache lookups with a Hash:
a = (1..1000000).to_a
h = Hash.new{|hash,key| hash[key] = true if a.include? key}
Pretty much what it does is create a default constructor for new hash values, then stores "true" in the cache if it's in the array (nil otherwise). This allows lazy loading into the cache, just in case you don't use every element.
This preserves 0's if your hash was [0,0,0,1,0]
hash = {}
arr.each_with_index{|el, idx| hash.merge!({(idx + 1 )=> el }) }
Returns :
# {1=>0, 2=>0, 3=>0, 4=>1, 5=>0}

Resources