Ruby Calling Join on an Array versus String - ruby-on-rails

I have a script that creates an array , then adds items to the array depending on certain circumstances. In most cases, the array will end up with several values inside of it. Occasionally, the array will only hold one value inside of it.
After preparing this array, I usually call .join(",") to create a comma-separated string of all the array values:
tags.join(",")
It works fine when the array has multiple values, but when it only has one value it throws an error:
NoMethodError: undefined method 'join' for "Whatever the array value": String
Any idea why this is? What is the easiest way to resolve this? Do I need to do an if statement to check if the variable is an array or string? Seems a bit silly...let me know if I am missing something here.

If obj is your object, you can write
[*obj].join
For example
arr = ["Fa", "bu", "lo", "us!"]
[*arr].join #=> "Fabulous!"
str = "Whoa!"
[*str].join #=> "Whoa!"
This works because
[*arr] #=> ["Fa", "bu", "lo", "us!"] == arr
[*str] #=> ["Whoa!"]
Similarly,
[*[1,2,3]].join #=> "123"
[*7].join #=> "7"

You can use join on an array as following way :
#array = ["this","is","join","method","example"]
#array.join(" ")
"this is join method example"
#array.join("_")
"this_is_join_method_example"

In the case of a single element (say, 'Hello'), you should be calling join on an array, not the string itself; for example, ['Hello'].join(",") rather than 'Hello'.join(","). Of course, if there's only one element join doesn't actually do anything, so you could just use a conditional if to skip it... but that's kinda ugly. Most of the time, I'd use the construction Array(tags).join(","). If passed a single string, that'll wrap it in an array; if passed an array, it's a noop, returning the array as-is.

Related

LuA How to sort table from lowest value without key changes [duplicate]

I have a key => value table I'd like to sort in Lua. The keys are all integers, but aren't consecutive (and have meaning). Lua's only sort function appears to be table.sort, which treats tables as simple arrays, discarding the original keys and their association with particular items. Instead, I'd essentially like to be able to use PHP's asort() function.
What I have:
items = {
[1004] = "foo",
[1234] = "bar",
[3188] = "baz",
[7007] = "quux",
}
What I want after the sort operation:
items = {
[1234] = "bar",
[3188] = "baz",
[1004] = "foo",
[7007] = "quux",
}
Any ideas?
Edit: Based on answers, I'm going to assume that it's simply an odd quirk of the particular embedded Lua interpreter I'm working with, but in all of my tests, pairs() always returns table items in the order in which they were added to the table. (i.e. the two above declarations would iterate differently).
Unfortunately, because that isn't normal behavior, it looks like I can't get what I need; Lua doesn't have the necessary tools built-in (of course) and the embedded environment is too limited for me to work around it.
Still, thanks for your help, all!
You seem to misunderstand something. What you have here is a associative array. Associative arrays have no explicit order on them, e.g. it's only the internal representation (usually sorted) that orders them.
In short -- in Lua, both of the arrays you posted are the same.
What you would want instead, is such a representation:
items = {
{1004, "foo"},
{1234, "bar"},
{3188, "baz"},
{7007, "quux"},
}
While you can't get them by index now (they are indexed 1, 2, 3, 4, but you can create another index array), you can sort them using table.sort.
A sorting function would be then:
function compare(a,b)
return a[1] < b[1]
end
table.sort(items, compare)
As Komel said, you're dealing with associative arrays, which have no guaranteed ordering.
If you want key ordering based on its associated value while also preserving associative array functionality, you can do something like this:
function getKeysSortedByValue(tbl, sortFunction)
local keys = {}
for key in pairs(tbl) do
table.insert(keys, key)
end
table.sort(keys, function(a, b)
return sortFunction(tbl[a], tbl[b])
end)
return keys
end
items = {
[1004] = "foo",
[1234] = "bar",
[3188] = "baz",
[7007] = "quux",
}
local sortedKeys = getKeysSortedByValue(items, function(a, b) return a < b end)
sortedKeys is {1234,3188,1004,7007}, and you can access your data like so:
for _, key in ipairs(sortedKeys) do
print(key, items[key])
end
result:
1234 bar
3188 baz
1004 foo
7007 quux
hmm, missed the part about not being able to control the iteration. there
But in lua there is usually always a way.
http://lua-users.org/wiki/OrderedAssociativeTable
Thats a start. Now you would need to replace the pairs() that the library uses. That could be a simples as pairs=my_pairs. You could then use the solution in the link above
PHP arrays are different from Lua tables.
A PHP array may have an ordered list of key-value pairs.
A Lua table always contains an unordered set of key-value pairs.
A Lua table acts as an array when a programmer chooses to use integers 1, 2, 3, ... as keys. The language syntax and standard library functions, like table.sort offer special support for tables with consecutive-integer keys.
So, if you want to emulate a PHP array, you'll have to represent it using list of key-value pairs, which is really a table of tables, but it's more helpful to think of it as a list of key-value pairs. Pass a custom "less-than" function to table.sort and you'll be all set.
N.B. Lua allows you to mix consecutive-integer keys with any other kinds of keys in the same table—and the representation is efficient. I use this feature sometimes, usually to tag an array with a few pieces of metadata.
Coming to this a few months later, with the same query. The recommended answer seemed to pinpoint the gap between what was required and how this looks in LUA, but it didn't get me what I was after exactly :- which was a Hash sorted by Key.
The first three functions on this page DID however : http://lua-users.org/wiki/SortedIteration
I did a brief bit of Lua coding a couple of years ago but I'm no longer fluent in it.
When faced with a similar problem, I copied my array to another array with keys and values reversed, then used sort on the new array.
I wasn't aware of a possibility to sort the array using the method Kornel Kisielewicz recommends.
The proposed compare function works but only if the values in the first column are unique.
Here is a bit enhanced compare function to ensure, if the values of a actual column equals, it takes values from next column to evaluate...
With {1234, "baam"} < {1234, "bar"} to be true the items the array containing "baam" will be inserted before the array containing the "bar".
local items = {
{1004, "foo"},
{1234, "bar"},
{1234, "baam"},
{3188, "baz"},
{7007, "quux"},
}
local function compare(a, b)
for inx = 1, #a do
-- print("A " .. inx .. " " .. a[inx])
-- print("B " .. inx .. " " .. b[inx])
if a[inx] == b[inx] and a[inx + 1] < b[inx + 1] then
return true
elseif a[inx] ~= b[inx] and a[inx] < b[inx] == true then
return true
else
return false
end
end
return false
end
table.sort(items,compare)

Eql command returns an empty array when using two parameters

When I am running the command like this:
related_attchments = related_documents.collect{|d| d.attachments.all}.flatten.select{|a| [“a”,“b”].eql?(a.attachment_type)}
the above command it is returning empty []
so basically I want to know whether I can use .eql? function with two parameters or not.
Because above statement works fine if i pass in below way:
related_attchments = related_documents.collect{|d| d.attachments.all}.flatten.select{|a| "a".eql?(a.attachment_type)}
Use include, like this:
related_attchments = related_documents.collect{|d| d.attachments.all}.flatten.select{|a| [“a”,“b”].include?(a.attachment_type)}
For your case use include? instead of eql?
.eql? use only one parameter, but on the other hand it can be an array as well. In your case ["a","b"] is comparing only to "a", or "b", so it will never be equal. If it would be the ["a","b"], then it would be equal. So, for your case use include? instead of eql as it will represent the comparison which you want to achieve.

Creating a where query in rails from an array

I need to make a where query from an array where each member of the array is a 'like' operation that is ANDed. Example:
SELECT ... WHERE property like '%something%' AND property like '%somethingelse%' AND ...
It's easy enough to do using the ActiveRecord where function but I'm unsure how to sanitize it first. I obviously can't just create a string and stuff it in the where function, but there doesn't seem to be a way possible using the ?.
Thanks
The easiest way to build your LIKE patterns is string interpolation:
where('property like ?', "%#{str}%")
and if you have all your strings in an array then you can use ActiveRecord's query chaining and inject to build your final query:
a = %w[your strings go here]
q = a.inject(YourModel) { |q, str| q.where('property like ?', "%#{str}%") }
Then you can q.all or q.limit(11) or whatever you need to do to get your final result.
Here's a quick tutorial on how this works; you should review the Active Record Query Interface Guide and the Enumerable documentation as well.
If you had two things (a and b) to match, you could do this:
q = Model.where('p like ?', "%#{a}%").where('p like ?', "%#{b}%")
The where method returns an object that supports all the usual query methods so you can chain calls as M.where(...).where(...)... as needed; the other query methods (such as order, limit, ...) return the same sort of object so you can chain those as well:
M.where(...).limit(11).where(...).order(...)
You have an array of things to LIKE against and you want to apply where to the model class, then apply where to what that returns, then again until you've used up your array. Thing that look like a feedback loop tend to call for inject (AKA reduce from "map-reduce" fame):
inject(initial) {| memo, obj | block } → obj
Combines all elements of enum by applying a binary operation, specified by a block or a symbol that names a method or operator.
If you specify a block, then for each element in enum the block is passed an accumulator value (memo) and the element [...] the result becomes the new value for memo. At the end of the iteration, the final value of memo is the return value for the method.
So inject takes the block's output (which is the return value of where in our case) and feeds that as an input to the next execution of the block. If you have an array and you inject on it:
a = [1, 2, 3]
r = a.inject(init) { |memo, n| memo.m(n) }
then that's the same as this:
r = init.m(1).m(2).m(3)
Or, in pseudocode:
r = init
for n in a
r = r.m(n)
If you're using AR, do something like Model.where(property: your_array) , or Model.where("property in (?)", your_array) This way, everything is sanitized
Let's say your array is model_array, try Array select:
model_array.select{|a|a.property=~/something/ and a.property=~/somethingelse/}
Of course you can use any regex as you like.

How to create object array in rails?

I need to know how to create object array in rails and how to add elements in to that.
I'm new to ruby on rails and this could be some sort of silly question but I can't find exact answer for that. So can please give some expert ideas about this
All you need is an array:
objArray = []
# or, if you want to be verbose
objArray = Array.new
To push, push or use <<:
objArray.push 17
>>> [17]
objArray << 4
>>> [17, 4]
You can use any object you like, it doesn't have to be of a particular type.
Since everything is an object in Ruby (including numbers and strings) any array you create is an object array that has no limits on the types of objects it can hold. There are no arrays of integers, or arrays of widgets in Ruby. Arrays are just arrays.
my_array = [24, :a_symbol, 'a string', Object.new, [1,2,3]]
As you can see, an array can contain anything, even another array.
Depending on the situation, I like this construct to initialize an array.
# Create a new array of 10 new objects
Array.new(10) { Object.new }
#=> [#<Object:0x007fd2709e9310>, #<Object:0x007fd2709e92e8>, #<Object:0x007fd2709e92c0>, #<Object:0x007fd2709e9298>, #<Object:0x007fd2709e9270>, #<Object:0x007fd2709e9248>, #<Object:0x007fd2709e9220>, #<Object:0x007fd2709e91f8>, #<Object:0x007fd2709e91d0>, #<Object:0x007fd2709e91a8>]
Also if you need to create array of words next construction could be used to avoid usage of quotes:
array = %w[first second third]
or
array = %w(first second third)

get first value in hash within hash

Is there a simple way, instead of looping my entire array to fetch the first value of every inner array.
so in essence I have the following;
array = [['test', 'test2'...], ['test' ....]]
so I want to grab array[#][0] and store the unqiue values.
EDIT
Is there a similar way to use the transpose method for arrays with Hash?
I essentially want to do the same thing
Hash = {1=> {1=> 'test', .....}, 2=> {1=> 'test',....}
so at the end I want to have something like new hash variable and leave my existing hash within hash alone.... = {1 => 'test', 2=> 'test2'}
Not sure if I fully understand the question, but if you have a 2 dimensional array (array in array), and you want to turn that into an array of the first element of the second dimension, you can use the map function
firsts = array.map {|array2| array2.first}
The way map works is that it turns one collection into a second collection by applying a function you provide (the block) to each element.
Maybe this?
array.transpose[0]

Resources