I want to push more arrays into this Hash? - arrays

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}

Related

Swift compare arrays, anyone has an idea how to solve it?

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"]

How do I split a string with two different delimiters in Ruby and convert it to two arrays?

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"]]

How to convert the position of an array into a single array?

What happens is that I have the following position of an array rows[0] = ["1", "2", "3", "4"] which stores certain data: what I want to do is to create a new array with the data that has the position 0 of the array rows so that, for example, I have a new vector = ["1", "2", "3", "4"], so that I could do, for example, console. log(new[0]); and have as output "1", and likewise with the other data of the new vector. I was thinking about doing it with some for or while loop, but I can't find the way to do it since row is of position 0.
you should try with destructuring
var rows = [];
rows[0] = ["1", "2", "3", "4"];
const [new] = rows
console.log(new[0]);

Swift : what is the right way to split up a [String] resulting in a [[String]] with a given example?

Starting with a large [String] and a given subarray size, what is the best way I could go about splitting up this array into smaller arrays? (The last array will be smaller than the given subarray size).
Concrete example:
Split up ["1","2","3","4","5","6","7","8","9"] with max split size 4
The code would produce [["1","2","3","4"],["4","5","6","7"],["7","8","9"]]
Obviously I could do this a little more manually, but I feel like in swift something like map() or reduce() may do what I want really beautifully.
You can map over the indices into you array:
extension Array {
func chunked(size: Int) -> [[Element]] {
let cnt = self.count
return stride(from: 0, to: cnt, by: size).map {
let end = Swift.min($0 + size, cnt)
return Array(self[$0..<end])
}
}
}
["1","2","3","4","5","6","7","8","9"].chunked(size: 4)
// -> [["1", "2", "3", "4"], ["5", "6", "7", "8"], ["9"]]
["1","2","3","4","5","6","7","8","9"].chunked(size: 3)
// -> [["1", "2", "3"], ["4", "5", "6"], ["7", "8", "9"]]

In Ruby, how do I calculate how close an element is to its neighbor?

I'm using Ruby 2.4. I have an array of strings, which are in fact numbers ...
["1", "2", "3", "7", "8", "9"]
How do I write an expression that will tell me the percentage of elements in the array (neglecting the last one) that have an absolute value difference of 1 with the element that follows it? So in the above, this is true for four out of the five elements, (since "7" has a difference of four following the "3" element), so I would expect the expression to return .8.
arr = ["1", "2", "3", "7", "8", "9"].map(&:to_i)
result = arr.each_cons(2).count { |a, b| (a - b).abs == 1 }
percentage = result / (arr.count - 1).to_f
#=> 0.8
Here are a couple of ways to do that.
arr = ["1", "2", "3", "7", "6", "8", "7"]
Step through the array and count the number of matches.
100 * arr[0..-2].each_index.count do |i|
ai, aip1 = arr[i], arr[i+1]
aip1 == ai.next || ai == aip1.next
end/(arr.size-1).to_f
#=> 66.66666666666667
Step with an enumerator
n = 0
enum = arr.to_enum
loop do
nxt, pk = enum.next, enum.peek
n += 1 if nxt.next == pk || pk.next == nxt
end
(100*n)/(arr.size-1).to_f
#=> 66.66666666666667
When all elements have been generated by the enumerator enum (which can also be defined arr.each) enum.peek raises a StopIteration exception (unless the array is empty, in which case enum.next raises the same exception). Kernel#loop handles that exception by breaking out of the loop.
Notice that there is no need to convert the strings to integers.

Resources