How to get rows as Arrays (not Hashes) in Sequel ORM? - ruby

In the Sequel ORM for Ruby, the Dataset class has an all method which produces an Array of row hashes: each row is a Hash with column names as keys.
For example, given a table T:
a b c
--------------
0 22 "Abe"
1 35 "Betty"
2 58 "Chris"
then:
ds = DB['select a, b, c from T']
ah = ds.all # Array of row Hashes
should produce:
[{"a":0,"b":22,"c":"Abe"},{"a":1,"b":35,"c":"Betty"},{"a":2,"b":58,"c":"Chris"}]
Is there a way built in to Sequel to instead produce an Array of row Arrays, where each row is an array of only the values in each row in the order specified in the query? Sort of how select_rows works in ActiveRecord? Something like this:
aa = ds.rows # Array of row Arrays
which would produce:
[[0,22,"Abe"],[1,35,"Betty"],[2,58,"Chris"]]
Note: the expression:
aa = ds.map { |h| h.values }
produces an array of arrays, but the order of values in the rows is NOT guaranteed to match the order requested in the original query. In this example, aa might look like:
[["Abe",0,22],["Betty",1,35],["Chris",2,58]]

Old versions of Sequel (pre 2.0) had the ability in some adapters to return arrays instead of hashes. But it caused numerous issues, nobody used it, and I didn't want to maintain it, so it was removed. If you really want arrays, you need to drop down to the connection level and use a connection specific method:
DB.synchronize do |conn|
rows = conn.exec('SQL Here') # Hypothetical example code
end
The actual code you need will depend on the adapter you are using.

DB[:table].where().select_map(:id)

If you want just an array of array of values...
DB['select * from T'].map { |h| h.values }
seems to work
UPDATE given the updated requirement of the column order matching the query order...
cols= [:a, :c, :b]
DB[:T].select{cols}.collect{ |h| cols.collect {|c| h[c]}}
not very pretty but guaranteed order is the same as the select order.
There does not appear to be a builtin to do this.
You could make a request for the feature.

I haven't yet found a built-in method to return an array of row arrays where the values in the row arrays are ordered by the column order in the original query. The following function does* although I suspect an internal method could be more effecient:
def rows( ds )
ret = []
column_keys = ds.columns # guaranteed to match query order?
ds.all { |row_hash|
row_array = []
column_keys.map { |column_key| row_array << row_hash[column_key] }
ret << row_array
}
ret
end
*This function depends on the order of the array returned by Dataset.columns. If this order is undefined, then this rows function isn't very useful.

have you tried this?
ds = DB['select a, b, c from T'].to_a
not sure it it works but give it a shot.

Related

How can I index the first column of the 2nd and 3d row in the following matrix in Python?

I've tried this
def matrix():
A = [[0,1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]]
return(A[1:2][0])
I want the function to return the value 5 and 9
If you would like to get the first element of the 2nd and 3rd rows it is:
def matrix():
A = [[0,1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]]
return (A[1][0], A[2][0])
This returns (5,9) as a tuple.
If you would like to parameterize it as such:
def matrix(rows):
# rows is a tuple or array like (1,2) with the indexes
A = [[0,1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]]
result = [] # empty list
for i in rows:
result.append(A[i][0])
return result
After calling the method like this: matrix((1,2)), it returns [5,9] as a list.

How i can perform request to tarantool like in mysql?

I need select from tarantool all datat by two values from one space.
How i can perform request to tarantool like in mysql?
select from aaa where a=1a22cadbdb or a=7f626e0123
Now i can make two requests:
box.space.logs:select({'1a22cadbdb'})
box.space.logs:select({'7f626e0123'})
but i don't know how to merge result into one ;(
Following code merge field[0] to lua table
a = box.space.logs:select({'1a22cadbdb'})
b = box.space.logs:select({'7f626e0123'})
c = { field_1 = a[0], field_2 = b[0] }
The select return tuple or tuples so you can extract value via [].
More details about select: http://tarantool.org/doc/book/box/box_index.html?highlight=select#lua-function.index_object.select
More details about tuple: http://tarantool.org/doc/book/box/box_tuple.html?highlight=tuple#lua-module.box.tuple
Nowadays Tarantool allows you to retrieve via SQL, for example box.execute([[select from "aaa" where "a"='1a22cadbdb' or "a"='7f626e0123';]]). You have to add the field names and types of aaa before doing this, with the format() function.
For me this work fine, but need make check for return from first select:
local res = {}
for k, v in pairs (box.space.email:select({email})[1]) do
if type(v) == 'string' then
table.insert(res, box.space.logs:select({v})[1])
end
end

Iterate over table in order of value

Lets say I have a table like so:
{
value = 4
},
{
value = 3
},
{
value = 1
},
{
value = 2
}
and I want to iterate over this and print the value in order so the output is like so:
1
2
3
4
How do I do this, I understand how to use ipairs and pairs, and table.sort, but that only works if using table.insert and the key is valid, I need to be loop over this in order of the value.
I tried a custom function but it simply printed them in the incorrect order.
I have tried:
Creating an index and looping that
Sorting the table (throws error: attempt to perform __lt on table and table)
And a combination of sorts, indexes and other tables that not only didn't work, but also made it very complicated.
I am well and truly stumped.
Sorting the table
This was the right solution.
(throws error: attempt to perform __lt on table and table)
Sounds like you tried to use a < b.
For Lua to be able to sort values, it has to know how to compare them. It knows how to compare numbers and strings, but by default it has idea how to compare two tables. Consider this:
local people = {
{ name = 'fred', age = 43 },
{ name = 'ted', age = 31 },
{ name = 'ned', age = 12 },
}
If I call sort on people, how can Lua know what I intend? I doesn't know what 'age' or 'name' means or which I'd want to use for comparison. I have to tell it.
It's possible to add a metatable to a table which tells Lua what the < operator means for a table, but you can also supply sort with a callback function that tells it how to compare two objects.
You supply sort with a function that receives two values and you return whether the first is "less than" the second, using your knowledge of the tables. In the case of your tables:
table.sort(t, function(a,b) return a.value < b.value end)
for i,entry in ipairs(t) do
print(i,entry.value)
end
If you want to leave the original table unchanged, you could create a custom 'sort by value' iterator like this:
local function valueSort(a,b)
return a.value < b.value;
end
function sortByValue( tbl ) -- use as iterator
-- build new table to sort
local sorted = {};
for i,v in ipairs( tbl ) do sorted[i] = v end;
-- sort new table
table.sort( sorted, valueSort );
-- return iterator
return ipairs( sorted );
end
When sortByValue() is called, it clones tbl to a new sorted table, and then sorts the sorted table. It then hands the sorted table over to ipairs(), and ipairs outputs the iterator to be used by the for loop.
To use:
for i,v in sortByValue( myTable ) do
print(v)
end
While this ensures your original table remains unaltered, it has the downside that each time you do an iteration the iterator has to clone myTable to make a new sorted table, and then table.sort that sorted table.
If performance is vital, you can greatly speed things up by 'caching' the work done by the sortByValue() iterator. Updated code:
local resort, sorted = true;
local function valueSort(a,b)
return a.value < b.value;
end
function sortByValue( tbl ) -- use as iterator
if not sorted then -- rebuild sorted table
sorted = {};
for i,v in ipairs( tbl ) do sorted[i] = v end;
resort = true;
end
if resort then -- sort the 'sorted' table
table.sort( sorted, valueSort );
resort = false;
end
-- return iterator
return ipairs( sorted );
end
Each time you add or remove an element to/from myTable set sorted = nil. This lets the iterator know it needs to rebuild the sorted table (and also re-sort it).
Each time you update a value property within one of the nested tables, set resort = true. This lets the iterator know it has to do a table.sort.
Now, when you use the iterator, it will try and re-use the previous sorted results from the cached sorted table.
If it can't find the sorted table (eg. on first use of the iterator, or because you set sorted = nil to force a rebuild) it will rebuild it. If it sees it needs to resort (eg. on first use, or if the sorted table was rebuilt, or if you set resort = true) then it will resort the sorted table.

Looking up an array of keys on an array of hashes in ruby like excel vlookup

This post is very similar to my previous one, but the data structures are different here:
Joining an array of keys to a hash with key value pairs like excel vlookup
My data from my Mysql2::Result comes back like this array of hashes:
data = [{"isbn" => "1234", "title"=>"apple"},{"isbn" => "5678", "title"=>"banana"},{"isbn" => "2121", "title"=>"car"}]
And my original list of isbns that I would like to compare is this array:
isbns = ["1234","2121", "5454", "5678"]
I'm seeking a function which uses the isbns array and returns a result like this:
result = [{"isbn"=>"1234","title"=>"apple"}, {"isbn"=> "2121", "title"=>"car"}, nil, {"isbn"=>"5678","title"=>"banana"}]
The "driving" array is the isbns... imagine doing a vlookup from isbns to data ... any items that are not in data, but in isbns should return nil. The original order of isbns should be returned, and the return data should be an array of hashes.
isbns.map { |isbn| data.find { |h| h["isbn"] == isbn} }
#=> [{"isbn"=>"1234", "title"=>"apple"}, {"isbn"=>"2121", "title"=>"car"}, nil, {"isbn"=>"5678", "title"=>"banana"}]
#Michael Kohl's answer is succinct and correct. However if these data sets are big, it's inefficient O(n*m/2). An alternative is to transform the data vector into a hash in O(m) then do the map in O(n) for a runtime of O(n+m).
data_lookup = data.inject({}) {|m,v| m[v["isbn"]] = v; m} # O(data.size)
result = isbns.map { |isbn| data_lookup[isbn] } # O(isbns.size)
If your data and isbn collections were of size 1000 each, this would be faster by a factor of 250.

Lua - Sorting a table alphabetically

I have a table that is filled with random content that a user enters. I want my users to be able to rapidly search through this table, and one way of facilitating their search is by sorting the table alphabetically. Originally, the table looked something like this:
myTable = {
Zebra = "black and white",
Apple = "I love them!",
Coin = "25cents"
}
I was able to implement a pairsByKeys() function which allowed me to output the tables contents in alphabetical order, but not to store them that way. Because of the way the searching is setup, the table itself needs to be in alphabetical order.
function pairsByKeys (t, f)
local a = {}
for n in pairs(t) do
table.insert(a, n)
end
table.sort(a, f)
local i = 0 -- iterator variable
local iter = function () -- iterator function
i = i + 1
if a[i] == nil then
return nil
else
return a[i], t[a[i]]
end
end
return iter
end
After a time I came to understand (perhaps incorrectly - you tell me) that non-numerically indexed tables cannot be sorted alphabetically. So then I started thinking of ways around that - one way I thought of is sorting the table and then putting each value into a numerically indexed array, something like below:
myTable = {
[1] = { Apple = "I love them!" },
[2] = { Coin = "25cents" },
[3] = { Zebra = "black and white" },
}
In principle, I feel this should work, but for some reason I am having difficulty with it. My table does not appear to be sorting. Here is the function I use, with the above function, to sort the table:
SortFunc = function ()
local newtbl = {}
local t = {}
for title,value in pairsByKeys(myTable) do
newtbl[title] = value
tinsert(t,newtbl[title])
end
myTable = t
end
myTable still does not end up being sorted. Why?
Lua's table can be hybrid. For numerical keys, starting at 1, it uses a vector and for other keys it uses a hash.
For example, {1="foo", 2="bar", 4="hey", my="name"}
1 & 2, will be placed in a vector, 4 & my will be placed in a hashtable. 4 broke the sequence and that's the reason for including it into the hashtable.
For information on how to sort Lua's table take a look here: 19.3 - Sort
Your new table needs consecutive integer keys and needs values themselves to be tables. So you want something on this order:
SortFunc = function (myTable)
local t = {}
for title,value in pairsByKeys(myTable) do
table.insert(t, { title = title, value = value })
end
myTable = t
return myTable
end
This assumes that pairsByKeys does what I think it does...

Resources