Related
We have some objets (about 100,000 objects), each object has a property with some integers (range from 1 to 20,000, at most 20 elements, no duplicated elements.):
For example:
object_1: [1, 4]
object_2: [1, 3]
object_3: [100]
And the problem is, we input a array of integer (called A), find out which objects hold the subset of A.
For example:
when A = [1], the output should be []
when A = [1, 4], the output should be [object_1]
when A = [1, 3, 4], the output should be [object_1, object_2]
The problem can be described in python:
from typing import List
# problem description
class Object(object):
def __init__(self, integers):
self.integers = integers
def size(self):
return len(self.integers)
object_1 = Object([1, 4])
object_2 = Object([1, 3])
object_3 = Object([100])
def _find_subset_objects(integers): # type: (List[int]) -> List[Object]
raise NotImplementedError()
def test(find_subset_objects=_find_subset_objects):
assert find_subset_objects([1]) == []
assert find_subset_objects([1, 4]) == [object_1]
assert find_subset_objects([1, 3, 4]) == [object_1, object_2]
Is there some algorithm or some data struct is aim to solve this kind of problem?
Store the objects in an array. The indices will be 0 ... ~100K. Then create two helper arrays.
First one with the element counts for every object. I will call this array obj_total(This could be ommited by calling the object.size or something similar if you wish.)
Second one initialized with zeroes. I will call it current_object_count.
For every integer property p where 0 < p <= 20000, create a list of indices where index i in the list means that the element is contained in the i-th object.
It is getting messy and I'm getting lost in the names. Time for the example with the objects that you used in the question:
objects = [[1, 4], [1, 3], [100]]
obj_total = [2, 2, 1]
current_object_count = [0, 0, 0]
object_1_ref = [0, 1]
object_2_ref = [ ]
object_3_ref = [1]
object_4_ref = [0]
object_100_ref = [100]
object_refs = [object_1_ref ,object_2_ref , ... , object_100_ref]
#Note that you will want to do this references dynamically.
#I'm writing them out only for the sake of clarity.
Now we are given the input array, for example [1, 3, 4]. For every element i in the array, we look we look at the object_i_ref. We then use the indices in the reference array to increase the values in the current_object_count array.
Whenever you increase a value in the current_object_count[x], you also check against the obj_total[x] array. If the values match, the object in objects[x] is a subset of the input array and we can note it down.
When you finish with the input array you have all the results.
I have the following code:
chartJsObject = [{label: "Label Stuff", datasets: []}]
i = 0
while i < 5 do
chartJsObject[i][:datasets] << [rand(10), rand(10)] if chartJsObject[i]
i+=1
end
While I expect datasets to include five sets of #s, like [9, 9], [1, 2] etc, I get:
chartJsObject # => [{"label":"Label Stuff","datasets":[[9,9]]}]
What am I doing wrong in the while loop?
chart_js_object has only one element, at index 0. So each call to chart_js_object[i] where i is anything other than zero is returning nil. This would cause an error, except that the conditional at the end of your operative provision is causing the code to ignore each iteration after the first.
Let's use Ruby standards for variable naming. I'll translate to snake_case. Also, while loops are pretty rare in Ruby. To perform an operation a specific number of times, you can just use the #times method.
So we end up with this:
>> 5.times { chart_js_object[0][:datasets] << [rand(10), rand(10)] }
>> chart_js_object
=> [{:label=>"Label Stuff", :datasets=>[[0, 4], [6, 0], [5, 4], [4, 6], [8, 6]]}]
The chartJsObject array has only one datum, so the array count is 1, and array index is chartJsObject[0]. The loop body runs only once, as the chartJsObject array has only one datum in it, and you have given the condition as
if chartJsObject[i]
That's the reason it gives you the result like that.
This question already has answers here:
What does the (unary) * operator do in this Ruby code?
(3 answers)
What does the * (star) mean in Ruby? [duplicate]
(1 answer)
Closed 7 years ago.
I read this code that is about quicksort with monkey-patching for the Array class.
class Array
def quicksort
return [] if empty?
pivot = delete_at(rand(size))
left, right = partition(&pivot.method(:>))
return *left.quicksort, pivot, *right.quicksort
end
end
I don't know what the star (*) sign seen at the start of *left.quicksort is. Can't we just use left.quicksort?
The star (in this case) stands for array unpacking. The idea behind it is that you want to get one array with the given elements, instead of array of array, element, array:
left = [1, 2, 3]
pivot = 4
right = [5, 6, 7]
[left, pivot, right] # => [[1, 2, 3], 4, [5, 6, 7]]
[*left, pivot, *right] # => [1, 2, 3, 4, 5, 6, 7]
The * takes a list of arguments and splits them into individual elements.
This allows you to return one un-nested array even when the left and right themselves return an array.
Regarding can't we just use left.quicksort did you give it a try?
def a()
return *[1,2,3], 4, *[5,6]
end
def b()
return [1,2,3], 4, *[5,6]
end
b()
=> [[1, 2, 3], 4, 5, 6]
a()
=> [1, 2, 3, 4, 5, 6]
Without the asterisk, you will have three values returned... the first and last value will be a single array with multiple values
[array1], pivot, [array2]
With the asterisk, the array values will be returned as separate components...
array1_value_1, array1_value_2, array1_value_3, ..., pivot, array2_value_1, array2_value2, array2_value_3, ...
New to Ruby; When I am working with arrays, is there a difference between Enumerable#each_with_index and Array#index I have been working with a multidimensional array in which I am trying to find the location of a given value. My code is able to pass all the tests when I use either one. Coordinates is the array I am using to hold the location of the given value (in this case 1)
field=[[1,0],[0,0]]
coordinates=[]
field.each_with_index do |item|
if item.index(1)
coordinates.push(field.index(item)).push(item.index(1))
end
end
Thanks in advance for the help.
Let's take a closer look at your code:
field=[[1,0],[0,0]]
coordindates = []
field.each_with_index do |item|
if item.index(1)
coordinates.push(field.index(item)).push(item.index(1))
end
end
Let:
enum = field.each_with_index
#=> #<Enumerator: [[1, 0], [0, 0]]:each_with_index>
As you see this returns an enumerator.
Ruby sees your code like this:
enum.each do |item|
if item.index(1)
coordinates.push(field.index(item)).push(item.index(1))
end
end
The elements of the enumerator will be passed into the block by Enumerator#each, which will call Array#each since the receiver, field is an instance of the class Array.
We can see the elements of enum by converting it to an array:
enum.to_a
#=> [[[1, 0], 0], [[0, 0], 1]]
As you see, it has two elements, each being an array of two elements, the first being an array of two integers and the second being an integer.
We can simulate the operation of each by sending Enumerator#next to enum and assigning the block variables to the value returned by next. As there is but one block variable, item, we have:
item = enum.next
#=> [[1, 0], 0]
That is quite likely neither what you were expecting nor what you wanted.
Next, you invoke Array#index on item:
item.index(1)
#=> nil
index searches the array item for an element that equals 1. If it finds one it returns that element's index in the array. (For example, item.index(0) #=> 1). As neither [1,0] nor 0 equals 1, index returns nil.
Let's rewind (and recreate the enumerator). You need two block variables:
field.each_with_index do |item, index|...
which is the same as:
enum.each do |item, index|...
So now:
item, index = enum.next
#=> [[1, 0], 0]
item #=> [1, 0]
index #=> 0
and
item.index(1)
#=> 0
I will let you take it from here, but let me mention just one more thing. I'm not advocating it, but you could have written:
field.each_with_index do |(first, second), index|...
in which case:
(first, second), index = enum.next
#=> [[1, 0], 0]
first #=> 1
second #=> 0
index #=> 0
See Ruby doc: http://ruby-doc.org/core-2.2.0/Array.html#method-i-index and http://ruby-doc.org/core-2.2.1/Enumerable.html#method-i-each_with_index
index is a method of Array, it detects whether an item exists in a specific Array, return the index if the item exists, and nil if does not exist.
each_with_index is a method of Enumerable mixin, it usually takes 2 arguments, first one is item and the second one is index.
So your sample could be simplified as:
field = [[1, 0], [0, 0]]
coordinates = []
field.each_with_index do |item, index|
item_index = item.index(1)
coordinates << index << item_index if item_index
end
puts coordinates.inspect # => [0, 0]
Note your field.index(item) is just index.
Array#index and Enumerable#each_with_index are not related whatsoever (functionally speaking), one is used to get the index of an object within an Array and the other one is used to walk through a collection.
Actually each_with_index is a mutation of the each method that additionally yields the index of the actual object within the collection. This method is very useful if you need to keep track of the current position of the object you are in. It saves you the trouble of creating and incrementing an additional variable.
For example
['a', 'b', 'c', 'd'].each_with_index do|char, idx|
puts "#{idx}) #{char}"
end
output:
0) a
1) b
2) c
3) d
Without each_with_index
idx = 0
['a', 'b', 'c', 'd'].each do|char|
puts "#{idx}) #{char}"
idx += 1
end
output:
0) a
1) b
2) c
3) d
To find the index of an object within a multidimensional Array you will have to iterate at least through all the rows of the matrix, like this (using each_with_index and index)
def find_position(matrix, obj)
matrix.each_with_index do|row, i|
return [i, j] if j = row.index(obj)
end
return nil
end
for example:
find_position([[2,3],[4,5]], 5) # => [1, 1]
Given that:
fields = [[1, 0], [0, 0]]
Enumerable#each_with_index passes each index as well as each object to the block:
fields.each_with_index do |field, idx|
puts "#{field}, #{idx}"
end
#=> [1, 0], 0
#=> [0, 0], 1
Array#index returns the index of the matching array element:
puts fields.index([1, 0])
#=> 0
In Ruby I have a multidimensional array, 4D;
choices[ii][jj][kk][ll].
I have another array;
data[kk][ll]
choices[ii][jj].size==data.size
choices[ii][jj][kk].size==data[kk].size
I would like to populate the last two dimensions of choices with the elements of data, as they are the same size I am looking for an approach which requires little code.
In MATLAB I know how to do this easily with subscript indexing; eg. choices[ii,jj,:,:]=data[:,:]. As well, in MATLAB I can add the matrix/2Darray easily.
How can this be done in Ruby?
EDIT: an example
bb=Array.new(2,4)
aa=Array.new(3,Array.new(2,0))
=> [[0, 0], [0, 0], [0, 0]]
irb(main):006:0> aa[1]=bb
=> [4, 4]
irb(main):007:0> aa
=> [[0, 0], [4, 4], [0, 0]]
This is ok, but for a 3D array, I get the array 'bb' copied into sections I don't want it to:
aa=Array.new(3,Array.new(2,Array.new(2,0)))
=> [[[0, 0], [0, 0]], [[0, 0], [0, 0]], [[0, 0], [0, 0]]]
irb(main):013:0> aa[2][1]=bb
=> [4, 4]
irb(main):014:0> aa
=> [[[0, 0], [4, 4]], [[0, 0], [4, 4]], [[0, 0], [4, 4]]]
I read the documentation on Array more carefully.
An array can also be created by explicitly calling ::new with zero, one (the initial size of the Array) or two arguments (the initial size and a default object).
ary = Array.new #=> []
Array.new(3) #=> [nil, nil, nil]
Array.new(3, true) #=> [true, true, true]
Note that the second argument populates the array with references to the same object. Therefore, it is only recommended in cases when you need to instantiate arrays with natively immutable objects such as Symbols, numbers, true or false.
To create an array with separate objects a block can be passed instead. This method is safe to use with mutable objects such as hashes, strings or other arrays:
Array.new(4) { Hash.new } #=> [{}, {}, {}, {}]
This is also a quick way to build up multi-dimensional arrays:
empty_table = Array.new(3) { Array.new(3) }
#=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
Which means that I was modifying the element which was referenced in multiple places. And I had to explicitly create a new Array object for each entry along the new dimensions I was adding, so in a way building the extra dimension incrementally. There seem to be multiple ways of doing this. One is this method of a block sent to Array, and another is to do an iterator on the dimension and make a new Array for each entry.
I also found this post which highlights the problem in very simple terms:>>
The wrong way, and the way I see people trying often is to say Array.new( 4, Array.new(4, 0) ). In other words, an array of 4 rows, each row being an array of 4 zeroes. And this appears to work at first. However, run the following code:
a = Array.new( 4, Array.new(4, 0) ) a[0][0] = 1 pp a
It looks simple. Make a 4x4 array of zeroes, set the top-left element to 1. But print it and we get…
[[1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0]]
It set the entire first column to 1, what gives? When we made the arrays, the inner-most call to Array.new gets called first, making a single row. A single reference to this row is then duplicated 4 times to fill the outer-most array. Each row is then referencing the same array. Change one, change them all.
Instead of passing a value to the Array.new method, we pass a block. The block is executed every time the Array.new method needs a new value. So if you were to say Array.new(5) { gets.chomp }, Ruby will stop and ask for input 5 times. So all we need to do is just create a new array inside this block. So we end up with Array.new(4) { Array.new(4,0) }. Now let's try that test case again.
a = Array.new(4) { Array.new(4, 0) } a[0][0] = 1 pp a
And it does just as you'd expect.
[[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]