How do I change the first elements of a 2 dimensional array? - arrays

I have an array
[[-20,23],[-80,65], ... []]
and I need
[["20",23],["80",65], ... []]
I have no idea how to deal with it.
Here is my code:
#posts = Post.featured_post.where(new_follow: true)
posts = (#posts.map { |post| "-#{ post[:ss_group_id] }_#{ post[:post_id] }" }).join(',') # here make parameters for request
posts = '"' + posts + '"'
posts_response = get_request(code_constructor('API.get', { posts: posts },[])) # here is response from API
noexist_posts = #posts.pluck(:vk_group_id, :post_id) - (posts_response[0].map { |h| h.values_at('owner_id', 'id') })
.map { |a| [a[0].abs.to_s, a[1]] } # here is what I want
I tried to find which posts don't exist.

A more inefficient, but cooler looking alternative to regular reassignment:
x.map { |first, *rest| [first.abs.to_s, *rest] }

You could do something like this
result = your_array.map{|a| [a[0].abs.to_s),a[1]]}

For some reason noone has posted the "regular reassignment" yet, so here it is (assuming you want to change the array in place):
x.each { |numbers| numbers[0] = numbers.first.abs.to_s }

Related

In Ruby, how can I sort an array of hashes

I am new to Ruby, could someone help?
I have some product data Json that I need to sort by the expiry date, however everything thing I have tried with .sort_by so far is erroring.
The Json is in this format
{"wh_Repeating":[
{
"wh": {
"Item_Number": "111166",
"Expiry_Date": "2023-05-05"
}
},
{
"wh": {
"Item_Number": "111167",
"Expiry_Date": "2023-05-01"
}
},
{
"wh": {
"Item_Number": "111168",
"Expiry_Date": "2023-05-09"
}
}]}
in Ruby that shows as
{:wh_Repeating=>[
{:wh=>{:Item_Number=>"111166", :Expiry_Date=>"2023-05-05"}},
{:wh=>{:Item_Number=>"111167", :Expiry_Date=>"2023-05-01"}},
{:wh=>{:Item_Number=>"111168", :Expiry_Date=>"2023-05-09"}}
]}
tried alsorts
latest attempt was
sorted = jsonIn["wh_Repeating"]
sorted.sort_by { |k,v| v[:"Expiry_Date"] }
puts sorted
which gave me
undefined method `sort_by' for nil:NilClass (NoMethodError)
(Exception)
Your hash keys are symbols not strings.
jsonIn["wh_Repeating"] should be jsonIn[:wh_Repeating]
Also, sorted.sort_by { |k,v| v[:"Expiry_Date"] } does not mutate sorted.
sort_by does not mutate the receiver. In other words, the value of sorted remains the same. There is a bang version (sort_by!) that does mutate (a side-effect) but the use of mutating functions is discouraged.
This does what you want to do.
jsonIn[:wh_Repeating].sort_by { |h| h.dig(:wh, :Expiry_Date) }
I would do it like this:
data = {:wh_Repeating=>
[{:wh=>{:Item_Number=>"111166", :Expiry_Date=>"2023-05-05"}},
{:wh=>{:Item_Number=>"111167", :Expiry_Date=>"2023-05-01"}},
{:wh=>{:Item_Number=>"111168", :Expiry_Date=>"2023-05-09"}}]}
data[:wh_Repeating].sort_by! { |hash| hash[:wh][:Expiry_Date] }
data
#=> {:wh_Repeating=>
[{:wh=>{:Item_Number=>"111167", :Expiry_Date=>"2023-05-01"}},
{:wh=>{:Item_Number=>"111166", :Expiry_Date=>"2023-05-05"}},
{:wh=>{:Item_Number=>"111168", :Expiry_Date=>"2023-05-09"}}]}
I have assumed the original hash (h below) is not to be mutated (modified).
h = { :wh_Repeating=>[
{:wh=>{:Item_Number=>"111166", :Expiry_Date=>"2023-05-05"}},
{:wh=>{:Item_Number=>"111167", :Expiry_Date=>"2023-05-01"}},
{:wh=>{:Item_Number=>"111168", :Expiry_Date=>"2023-05-09"}}
]
}
As this hash has a single key (:wh_Repeating), we can simply write the structure of the desired hash as
{ :wh_Repeating=>... }
and then compute the value of :wh_Repeating.
{ :wh_Repeating=>h[:wh_Repeating].sort_by { |g| g[:wh][:Expiry_Date] } }
#=> { :wh_Repeating=>[
# {:wh=>{:Item_Number=>"111167", :Expiry_Date=>"2023-05-01"}},
# {:wh=>{:Item_Number=>"111166", :Expiry_Date=>"2023-05-05"}},
# {:wh=>{:Item_Number=>"111168", :Expiry_Date=>"2023-05-09"}}
# ]
# }
The original hash h is unchanged, which can be easily verified.

Correct way to search an Array instead of where

How to query search an Array with where? What's the correct way?
U have an association like this:
# Foo has many bars
Foo.first.bars
Controller:
def index
#bars = []
#datas = Foo.where(email: current_user.email)
#datas.map { |d| #bars.push(d.bar).where("name like ?", "%#{params[:email]}%") }
respond_to do |format|
format.html
format.json { render json: #bars }
end
end
Instead of where for Array, what is the correct query term?
You can use the select method to filter out values in an array given a certain condition.
[1,2,3,4,5].select { |num| num.even? } #=> [2, 4]
Or for your particular example:
#bars = #datas.map { |d| d.bars }.select { |b| b.name.include? params[:email] }
However, since you actually don't have an array of bars and would have to create it, this is simply an unnecessary step and a more straightforward solution would be:
#datas = Foo.where(email: current_user.email)
# #bars is an array
#bars = #datas.map { |d| d.bars.where("name like ?", "%#{params[:email]}%") }
or
# #bars is an ActiveRecord object
#bars = Bar.where(id: #datas.pluck(:id)).where("name like ?", "%#{params[:email]}%")

Search and use of Strings in 2D Arrays

I got a 2D array where I want to fetch data from the 2nd dimension based on the 1st, but I dont understand how to set it up in Swift 2 since the old for-loop function is deprecated.
Based on the name (Burt) I want to present the phone-No and Group.
myArray: [[String]] = [["Adam", "123456", "Group1"], ["Burt", "251436", "Group2"], ["Cesar", "918273", "Group3"], ["David", "552277", "Group4"]
For i in 0..myArray.count {
If myArray[i][0] == "Burt" {
phoneNoLabel.text = myArray[i][1]
  GroupNoLabel.text = myArray[i][2]
}
}
This is how I solved it with the help of Tarun Seera.
let myArray = [["Adam", "123456", "Group1"], ["Burt", "251436", "Group2"], ["Cesar", "918273", "Group3"], ["David", "552277", "Group4"]]
var user: String = "Burt"
var phoneNo: String = ""
var groupNo: String = ""
for i in myArray {
if i[0] == user {
phoneNo = i[1]
groupNo = i[2]
}
}
You can also make entities (NSObject)array and use predicate to achieve the same thing and still if you want this form 2d array you can use below code
let myArray = [["Adam", "123456", "Group1"], ["Burt", "251436", "Group2"], ["Cesar", "918273", "Group3"], ["David", "552277", "Group4"]]
for i in myArray {
if i[0] == "Burt" {
print("Hurrey I am in.. my name is: \(i[0]) my Id is:\(i[1]) and my gourp is:\(i[2])")
}
}
for i in 0..<myArray.count {
if myArray[i][0] == "Burt" {
phoneNoLabel.text = myArray[i][1]
GroupNoLabel.text = myArray[i][2]
}
}
Use
..<
instead of just
..
Your problem is, that i is going from 0 to myArray.count - which is 4 .. that means your i is going 0,1,2,3,4 = you have 5 times i. Your array only has 4 "items".
for i in 1...myArray.count{
if myArray[i-1][0] == "Burt" {
phoneNoLabel.text = myArray[i-1][1]
GroupNoLabel.text = myArray[i-1][2]
}
}
or
for i in 0...myArray.count-1{
if myArray[i][0] == "Burt" {
phoneNoLabel.text = myArray[i][1]
GroupNoLabel.text = myArray[i][2]
}
}
should solve your problem.
As an alternative to explicit looping, you could use a functional programming approach
let searchForUser = "Burt"
let userInfo = Array(myArray
.flatMap{ $0.first == searchForUser ? $0.suffixFrom(1) : nil }
.flatten())
print(userInfo) // ["251436", "Group2"]
For you specific example, the user info you're after is readily obtainable from the userInfo array
phoneNoLabel.text = userInfo[0] // 251436
groupNoLabel.text = userInfo[1] // Group2
Note here that I've renamed GroupNoLabel variable (UILabel?) from the example in your question to groupNoLabel, as variables in Swift should, by convention, use camelCase names (and not CamelCase, as is used e.g. for types).

Merge nested hash without overwritting in Ruby

After checking this Ruby convert array to nested hash and other sites I am not able to achieve the following convertion:
I have this:
{"a"=>"text"}
{"b"=>{"x"=>"hola"}}
{"b"=>{"y"=>"pto"}
}
and I want to obtain:
{"a"=>text,
b=>{"x" => "hola",
"y" => "pto"
}
}
Until now the code seems like this:
tm =[[["a"],"text"],[["b","x"],"hola"],[["b","y"],"pto"]]
q = {}
tm.each do |l|
q = l[0].reverse.inject(l[1]) { |p, n| { n => p } }
i += 1
end
I tried with merge, but it overwrites the keys!. I tried also this How can I merge two hashes without overwritten duplicate keys in Ruby? but it keeps overwritting.
Update:
How can I do it for an undefined nested hash (level) ? hash[key1][key2][key3]... = "value"
{"a"=>"text"},
{"b"=>{"x"=>"hola"},
{"b"=>{"y"=>"pto"},
{"c"=>{"g"=>{"k" => "test1"}},
...
}
You could use merge with a block to tell Ruby how to handle duplicate keys:
a = {"a"=>"text"}
b = {"b"=>{"x"=>"hola"}}
c = {"b"=>{"y"=>"pto"}}
a.merge(b).merge(c) { |key, left, right| left.merge(right) }
#=> {"a"=>"text", "b"=>{"x"=>"hola", "y"=>"pto"}}
For Rails there is the deep_merge function for ActiveSupport that does exactly what you ask for.
You can implement the same for yourself as follows:
class ::Hash
def deep_merge(second)
merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
self.merge(second, &merger)
end
end
Now,
h1 = {"a"=>"text"}
h2 = {"b"=>{"x"=>"hola"}}
h3 = {"b"=>{"y"=>"pto"}}
h1.deep_merge(h2).deep_merge(h3)
# => {"a"=>"text", "b"=>{"x"=>"hola", "y"=>"pto"}}

Groovy ConfigSlurper Configure Arrays

I am trying to create a config that would look something like this:
nods = [
nod {
test = 1
},
nod {
test = 2
}
]
and then use configSlurper to read it but the "node" objects appear to be null after the read.
Here is my code:
final ConfigObject data = new ConfigSlurper().parse(new File("config.dat").toURI().toURL())
println data.nods
and the output:
[null, null]
What am I doing wrong?
Thanks!
It think I resolved it this way:
config {
nods = [
['name':'nod1', 'test':true],
['name':'nod2', 'test':flase]
]
}
And then using it like:
config = new ConfigSlurper().parse(new File("config.groovy").text)
for( i in 0..config.config.nods.size()-1)
println config.config.nods[i].test
Hope this helps someone else!!
You have to be careful when using ConfigSlurper when doing this sort of thing.
For example your solution will actually produce the following output:
true
[:]
If you look carefully you will notice that there is a typo on the second array value flase instead of false
The following:
def configObj = new ConfigSlurper().parse("config { nods=[[test:true],[test:false]] }")
configObj.config.nods.each { println it.test }
should produce the correct result:
true
false
I tried to parse with ConfigSlurper something like this:
config {sha=[{from = 123;to = 234},{from = 234;to = 567}]}
The array "sha" was far from what expected.
To get "sha" as an array of ConfigObjects I used a helper:
class ClosureScript extends Script {
Closure closure
def run() {
closure.resolveStrategy = Closure.DELEGATE_FIRST
closure.delegate = this
closure.call()
}
}
def item(closure) {
def eng = new ConfigSlurper()
def script = new ClosureScript(closure: closure)
eng.parse(script)
}
this way I get an array of ConfigObjects:
void testSha() {
def config = {sha=[item {from = 123;to = 234}, item {from = 234;to = 567}]}
def xx = item(config)
assertEquals(123, xx.sha[0].from)
}

Resources