I have one array like below
[["GJ","MP"],["HR","MH"],["MP","KL"],["KL","HR"]]
And I want result like below
"GJ, MP, KL, HR, MH"
First element of array ["GJ","MP"]
Added is in the answer_string = "GJ, MP"
Now Find MP
which is the last element of this array in the other where is should be first element like this ["MP","KL"]
after this I have to add KL
in to the answer_string = "GJ, MP, KL"
This is What I want as output
CodePudding user response:
d = [["GJ","MP"],["HR","MH"],["MP","KL"],["KL","HR"]]
o = [] # List for output
c = d[0][0] # Save the current first object
loop do # Keep looping through until there are no matching pairs
o.push(c) # Push the current first object to the output
n = d.index { |a| a[0] == c } # Get the index of the first matched pair of the current `c`
break if n == nil # If there are no found index, we've essentially gotten to the end of the graph
c = d[n][1] # Update the current first object
end
puts o.join(',') # Join the results
Updated as the question was dramatically changed. Essentially, you navigating a graph.
CodePudding user response:
Given
ary = [["GJ","MP"],["HR","MH"],["MP","KL"],["KL","HR"]]
(where each element is in fact an edge in a simple graph that you need to traverse) your task can be solved in a quite straightforward way:
acc = ary.first.dup
ary.size.times do
# Find an edge whose "from" value is equal to the latest "to" one
next_edge = ary.find { |a, _| a == acc.last }
acc << next_edge.last if next_edge
end
acc
#=> ["GJ", "MP", "KL", "HR", "MH"]
Bad thing here is its quadratic time (you search through the whole array on each iteration) that would hit you badly if the initial array is large enough. It would be faster to use some auxiliary data structure with the faster lookup (hash, for instance). Smth. like
head, *tail = ary
edges = tail.to_h
tail.reduce(head.dup) { |acc, (k, v)| acc << edges[acc.last] }
#=> ["GJ", "MP", "KL", "HR", "MH"]
(I'm not joining the resulting array into a string but this is kinda straightforward)
CodePudding user response:
Assumptions:
a
is anArray
or aHash
a
is in the form provided in the Original Post- For each element
b
ina
b[0]
is unique
First thing I would do is, if a
is an Array
, then convert a
to Hash
for faster easier lookup up (this is not technically necessary but it simplifies implementation and should increase performance)
a = [["GJ","MP"],["HR","MH"],["MP","KL"],["KL","HR"]]
a = a.to_h
#=> {"GJ"=>"MP", "HR"=>"MH", "MP"=>"KL", "KL"=>"HR"}
Then we can use a recursive method to lookup the path from a given key to the end of the path. Default key is a[0][0]
def navigation(h,key:h.keys.first)
return unless h.key?(key)
[key, *navigation(h,key:h[key]) || h[key]].join(",")
end
Explanation:
navigation(h,key:h.keys.first)
- Hash to traverse and the starting point for traversalreturn unless h.key?(key)
if theHash
does not contain thekey
at all return thenil
(end of the chain)[key, *navigation(h,key:h[key]) || h[key]].join(",")
- build aArray
ofkey
and the recursive result of looking up the value for thatkey
if the recursion returnsnil
then append the last value. Then simply convert theArray
to aString
joining the elements with a comma.
Usage:
a = [["GJ","MP"],["HR","MH"],["MP","KL"],["KL","HR"]].to_h
navigate(a)
#=> "GJ,MP,KL,HR,MH"
navigate(a,key: "KL")
#=> "KL,HR,MH"
navigate(a,key: "X")
#=> nil
CodePudding user response:
I use arr.size.times
to loop
def check arr
new_arr = arr.first #new_arr = ["GJ","MP"]
arr.delete_at(0) # remove the first of arr. arr = [["HR","MH"],["MP","KL"],["KL","HR"]]
arr.size.times do
find = arr.find {|e| e.first == new_arr.last}
new_arr << find.last if find
end
new_arr.join(',')
end
array = [["GJ","MP"],["HR","MH"],["MP","KL"],["KL","HR"]]
p check(array)
#=> "GJ,MP,KL,HR,MH"