Related
Could someone tell me how I can solve this problem? I have two arrays in array 1 change values, array 2 has to synchronize with the first one, but without losing the value positions. I have tried with difference(from:) but it reorders the values of array 2. Here as it should be, thank you very much for your help.
let array1 = ["01", "06", "17", "22", "33", "45", "04"]
var array2 = ["04", "17", "22", "10", "01", "34"]
//
...
// Result
var array2 = ["04", "17", "22", "01", "06", "33", "45"]
The order of the values in array 2 must remain the same, delete those missing from array 1 and add those missing from array 1 to the end of array 2.
Naive solution:
Copy array1 to a temporary var temp
Loop through the indexes of temp in reverse order. If a value from temp exists in array2, remove it.
Append temp to array2.
That would have poor (roughly O(n^2), or rather O(array1.count*array2.count)) time performance for large arrays, since the array contains() function is O(n). You could speed it up by using a set to track items in array2.
This is the best solution I can get 😉
let array1 = ["01", "06", "17", "22", "33", "45", "04"]
var array2 = ["04", "17", "22", "10", "01", "34"]
let remove = (array2.filter{!array1.contains($0)})
let append = (array1.filter{!array2.contains($0)})
for i in remove {
array2 = array2.filter {$0 != i}
}
array2.append(contentsOf: append)
print("array2:\(array2)")
// array2:["04", "17", "22", "01", "06", "33", "45"]
I have a string
"Param 1: 1, Some text: 2, Example3: 3, Example4: 4"
and I'd like to convert it into an arrays:
["Param 1","Some text","Example3","Example4"]
[1,2,3,4]
How?
Here's a one liner that uses Multiple Assignment to create 2 new named arrays:
a1, a2 = str.split(", ").map{|x| x.split(": ")}.transpose
a1 #=> ["Param 1", "Some text", "Example3", "Example4"]
a2 #=> ["1", "2", "3", "4"]
Although most of this solution has already been mentioned in one form or another in previous suggestions, I prefer this combined approach over others mentioned for a few reasons:
It doesn't utilize regex which makes it execute quicker than some of the other suggestions. Actually, after running a few quick benchmarks, it looks like it actually executes faster than the other non-regex solution listed so far as well.
It simultaneously creates 2 unique and individually named arrays to work with (as opposed to just creating an array with 2 sub arrays).
It carries out the whole operation with one line.
There are plenty of ways to do it in Ruby.
You can first split by pairs' delimiter (comma) and then use map to split further by key/pair delimiter (colon):
pairs = s.split(/,\s*/).map { |s| s.split(/:\s*/) }
keys = pairs.map(&:first)
values = pairs.map(&:last)
(here and below s is your original string)
You can use scan to match keys/values in a single call (disclaimer: it does NOT mean this is more efficient - regexps aren't magic)
pairs = s.scan(/(?<key>[^:]+):\s*(?<value>[^,]+)[,\s]*/)
keys = pairs.map(&:first)
values = pairs.map(&:last)
(named captures aren't necessary here - with scan they don't give any benefits - but I put them to make regexp arguably a bit more readable)
You can split by all delimiters and then use Enumerable#partition to separate keys from values, smth. like:
keys, values = s.split(/:\s*|,\s*/).partition.with_index { |_, i| i.even? }
etc...
Input
a = "Param 1: 1, Some text: 2, Example3: 3, Example4: 4"
Code
obj= a.split(',').map { |x| x.split(':') }
p obj.map(&:first).map(&:strip)
p obj.map(&:last)
Result
["Param 1", "Some text", "Example3", "Example4"]
[" 1", " 2", " 3", " 4"]
You can use String#split with a regular expression, then pair the returned values and transpose:
str = "Param 1: 1, Some text: 2, Example3: 3, Example4: 4"
str.split(/[:,] +/).each_slice(2).to_a.transpose
#=> [["Param 1", "Some text", "Example3", "Example4"],
# ["1", "2", "3", "4"]]
The steps are as follows.
a = str.split(/[:,] +/)
#=> ["Param 1", "1", "Some text", "2", "Example3", "3", "Example4", "4"]
The regular expression reads, "match a colon or comma followed by one or more spaces".
enum = a.each_slice(2)
#=> #<Enumerator: ["Param 1", "1", "Some text", "2", "Example3",
# "3", "Example4", "4"]:each_slice(2)>
b = enum.to_a
#=> [["Param 1", "1"], ["Some text", "2"], ["Example3", "3"],
# ["Example4", "4"]]
b.transpose
#=> [["Param 1", "Some text", "Example3", "Example4"],
# ["1", "2", "3", "4"]]
Here is a second way to perform the calculation that I present without explanation, except to say that it uses the form of String#gsub that takes one argument and no block, returning an enumerator that can be chained to Enumerator#with_object. This form of gsub, unlike the others, does not perform character substitutions (and therefore may be considered misnamed). Rather, the enumerator generates and returns matches of its argument, here a regular expression.
str.gsub(/[a-z][a-z ]+\d*(?=:)|\d+(?![^,])/i).with_object([[],[]]) do |s,(a,b)|
(s[0].match?(/\d/) ? b : a) << s
end
#=> [["Param 1", "Some text", "Example3", "Example4"],
# ["1", "2", "3", "4"]]
I'm working with knex in a node.js project on a PostgreSQL db. Will be using knex.schema.raw (raw SQL) to accomplish this.
I need to update all instances of a grade name ("1st", etc) in the "grades" array of a json object in a jsonb column. "grades" are one value in the whole json object, which is a lesson.
The array currently contains something like
"grades": ["Pre-K", "K", "4th", "5th", "6th", "7th", "8th"] and it needs to become "grades": ["PK", "K", "4", "5", "6", "7", "8"].
Basically I need any instances of
["Pre-K", "K", "1st", 2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th", "10th", "11th", "12th"]
to be
["PK", "K", "1", 2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"]
Is there a way to check the contents of a jsonb array, get the index of a grade, and update that index with the desired grade? Or another way to transform array data in a jsonb type column?
(My initial idea was to create a list of every permutation of combination of ["Pre-K", "K", "1st", 2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th", "10th", "11th", "12th"], and just swap out the desired array out of data that exists, but that seems a bit ungainly, though technically possible. With this, though, I would still need to find the index of item in array in jsonb cell.)
Use a regular expression to eliminate redundant substrings.
update my_table
set json_col = jsonb_set(
json_col,
'{grades}',
(
select jsonb_agg(regexp_replace(value, 're-|st|nd|rd|th', ''))
from jsonb_array_elements_text(json_col->'grades')
)
);
Db<>fiddle.
A simpler and faster version (though might be considered a bit hacky):
update my_table
set json_col = jsonb_set(
json_col,
'{grades}',
regexp_replace(json_col->>'grades', 're-|st|nd|rd|th', '', 'g')::jsonb
)
Read more about POSIX Regular Expressions.
i want to push an array into this part, i'm a newbie in Ruby
#edge_weights = {[position, position2] => node_distance}
That is a Hash? i think i want to push some other hashes of the same way to have a result like this:
{["1", "2"]=>2445, ["2", "3"]=>2015, ["2", "4"]=>1547, ["3", "4"]=>939, ["5", "1"]=>1548}
Not like this:
{["1", "2"]=>111},{["2", "3"]=>222},{["1", "3"]=>333}
How can i achieve this?. Sorry for my bad english :(
Presumably you will begin with some data such as the following array of arrays:
arr = [["1", "2", 2445], ["2", "3", 2015], ["2", "4", 1547],
["3", "4", 939], ["5", "1", "7", 1548], ["1", "2", -71]]
Step one is to create an empty hash:
h = {}
Now iterate over the elements of arr to build the hash h.
arr.each do |a|
*first, last = a
h[first] = last
end
#=> [["1", "2", 2445], ["2", "3", 2015], ["2", "4", 1547],
# ["3", "4", 939], ["5", "1", "7", 1548], ["1", "2", -71]]
We want the value of h, not the above return value.
h #=> {["1", "2"]=>-71, ["2", "3"]=>2015, ["2", "4"]=>1547,
# ["3", "4"]=>939, ["5", "1"]=>1548, ["5", "1", "7"]=>1548}
Note that Ruby's splat operator1 is used to break up an array in various ways:
*first, last = ["5", "1", "7", 1548]
first
#=> ["5", "1", "7"]
last
#=> 1548
Is the result above for h what you were expecting? Recall that hashes have unique keys. After the first element of arr is passed to the block we execute
h[["1", "2"]] = 2445
so that h becomes { ["1", "2"]=>2445 }. Later, when the last element of arr--which has the same key (["1", "2"])--is passed to the block, we execute
h[["1", "2"]] = -71
which overwrites the value of that key. If you'd prefer to keep the value of the first key encountered you could write
arr.each do |a|
*first, last = a
h[first] = last unless h.key?(first)
end
See Hash#key? (aka, has_key? and include?). (Aside: you could write ...if !h.key?(first), ! read not, but it's generally clearer to avoid negation by using unless.)
The "Ruby way" of writing the original construct is to use the method Enumerable#each_with_object and to splat the block variables a:
arr.each_with_object({}) do |(*first, last),h|
h[first] = last
end
#=> {["1", "2"]=>-71, ["2", "3"]=>2015, ["2", "4"]=>1547,
# ["3", "4"]=>939, ["5", "1"]=>1548, ["5", "1", "7"]=>1548}
This avoids the need to use a separate statement to create an empty hash and the code block returns the value of h.
(Don't worry if you don't understand this.)
One other common way to construct a hash is to use the method Hash#update (aka merge!):
arr.each_with_object({}) do |(*first, last),h|
h.update({ first=>last })
end
Note Ruby allows a shorthand version of the second line:
h.update(first=>last)
1 See "Multiple variable assignment" here.
you can pass array as key and assign value to it:
> edge_weights = {}
> edge_weights[["1","2"]] = 2445
> edge_weights[["2", "4"]] = 1547
> edge_weights
#=> {["1", "2"]=>2445, ["2", "4"]=>1547}
I'm using Ruby 2.4. I have an array of strings, which are themselves numbers. So something like
["1", "2", "3", "5"]
How do I check that the integer version of every element in the array (except the first) is greater than the one before it? So for instance the function performed on the above would return true, but an array like
["1", "5", "4", "6"]
would return false (because "4" is not greater than "5".
An alternative way to phrase your predicate is: "For all consecutive pairs of numbers, is it true that the second is greater than the first"? This can be almost directly expressed in code:
ary.map(&:to_i).each_cons(2).all? {|first, second| second > first }
By the way: this property is called "strict monotonicity".
You can use Enumerable#sort_by to see if the arr is already sorted by numerical value:
arr = ["1", "2", "3", "5"]
arr.uniq.sort_by(&:to_i) == arr
#=> true
If the elements are not unique, then the array fails automatically. Since that means two elements are of the same value i.e. one is not greater than the other.