bob smith
bob smith

Reputation: 33

Sort an array that are merged together

I have 2 strings that I made into an array to sort then to convert back into a string. But, in my test in my response.body The given string is sorted differently. I have a method that takes 2 strings and removes the headers from both and mergers the array and sorts it. But getting different results. How can I get the desired results of the below response.body string

string1 = "Category Name,Code,Enabled?,Category Hidden?\nPRESENT AVAIALBLE,PRESENT AVAILABLE,No,No,\nBUG AVAILABLE,BUG,No,No,\nBUG,BUG,No,No,\nPRESENT,PRESENT,No,No\n"
string2 = "Category Name,Code,Enabled?,Category Hidden?\nBUG,BUG,No,No,\nBUG AVAILABLE,BUG,No,No,\nEXAMPLE 1,EXAMPLE 1,Yes,No,\nEXAMPLE 2,EXAMPLE 2,Yes,No,\nPRESENT AVAIALBLE,PRESENT AVAILABLE,No,No,\nPRESENT,PRESENT,No,No\n"

how would I get that array to be sorted as the response.body string before inserting the header "Category Name,Code,Enabled?,Category Hidden?"

response.body string

"Category Name,Code,Enabled?,Category Hidden?
BUG,BUG,No,No,
BUG AVAILABLE,BUG,No,No,
EXAMPLE 1,EXAMPLE 1,No,No,
EXAMPLE 2,EXAMPLE 2,Yes,No,
PRESENT,PRESENT,No,No"
PRESENT AVAIALBLE,PRESENT AVAILABLE,No,No"

My output from method

"Category Name,Code,Enabled?,Category Hidden?
BUG AVAILABLE,BUG,No,No,
BUG,BUG,No,No,
EXAMPLE 1,EXAMPLE 1,No,No,
EXAMPLE 2,EXAMPLE 2,Yes,No,
PRESENT AVAIALBLE,PRESENT AVAILABLE,No,No,
PRESENT,PRESENT,No,No"

method I wrote

def merge(string1, string2)
  string1 = string1.split("\n") # Split into array.
  headers = string1.first # Get headers.
  string1.shift # Remove headers.
  string2 = string2.split("\n")[1..-1] # Remove headers.
  final = (string1 + string2).sort.unshift(headers).join("\n") + "\n" # Create merged sorted string.
end

desired result wanted

"Category Name,Code,Enabled?,Category Hidden?
BUG,BUG,No,No,
BUG AVAILABLE,BUG,No,No,
EXAMPLE 1,EXAMPLE 1,No,No,
EXAMPLE 2,EXAMPLE 2,Yes,No,
PRESENT,PRESENT,No,No"
PRESENT AVAIALBLE,PRESENT AVAILABLE,No,No"

Upvotes: 3

Views: 79

Answers (1)

Cary Swoveland
Cary Swoveland

Reputation: 110675

Here are three ways to do that.

I assume you are given two strings:

str1 = "Category Name,Code,Enabled?,Category Hidden?\nBUG,BUG,No,No\nEXAMPLE 1,EXAMPLE 1,No,No\nPRESENT,PRESENT,No,No"
str2 = "Category Name,Code,Enabled?,Category Hidden?\nBUG AVAILABLE,BUG,No,No\nEXAMPLE 2,EXAMPLE 2,Yes,No\nPRESENT AVAILABLE,PRESENT AVAILABLE,No,No"

Then

header, *body1 = str1.split("\n")
  #=> ["Category Name,Code,Enabled?,Category Hidden?",
  #    "BUG,BUG,No,No",
  #    "EXAMPLE 1,EXAMPLE 1,No,No",
  #    "PRESENT,PRESENT,No,No"]

so

header
  #=> "Category Name,Code,Enabled?,Category Hidden?"
body1
  #=> ["BUG,BUG,No,No",
  #    "EXAMPLE 1,EXAMPLE 1,No,No",
  #    "PRESENT,PRESENT,No,No"]

and

_, *body2      = str2.split("\n")
  #=> ["Category Name,Code,Enabled?,Category Hidden?",
  #    "BUG AVAILABLE,BUG,No,No",
  #    "EXAMPLE 2,EXAMPLE 2,Yes,No",
  #    "PRESENT AVAILABLE,PRESENT AVAILABLE,No,No"]

so

_ #=>  "Category Name,Code,Enabled?,Category Hidden?"
body2
  #=> ["BUG AVAILABLE,BUG,No,No",
  #    "EXAMPLE 2,EXAMPLE 2,Yes,No",
  #    "PRESENT AVAILABLE,PRESENT AVAILABLE,No,No"]

We may then compute the desired string.

str = [header].concat(body1.zip(body2).flatten).join("\n")
  #=> "Category Name,Code,Enabled?,Category Hidden?\nBUG,BUG,No,No\nBUG AVAILABLE,BUG,No,No\nEXAMPLE 1,EXAMPLE 1,No,No\nEXAMPLE 2,EXAMPLE 2,Yes,No\nPRESENT,PRESENT,No,No\nPRESENT AVAILABLE,PRESENT AVAILABLE,No,No"

which when displayed appears as follows.

puts str
Category Name,Code,Enabled?,Category Hidden?
BUG,BUG,No,No
BUG AVAILABLE,BUG,No,No
EXAMPLE 1,EXAMPLE 1,No,No
EXAMPLE 2,EXAMPLE 2,Yes,No
PRESENT,PRESENT,No,No
PRESENT AVAILABLE,PRESENT AVAILABLE,No,No

See Array#concat, Array#zip, Array#flatten and Array#join.

The variable _ in _, *body2 = str2.split("\n") is so-named to tell the reader that it is not used in subsequent calculations. Sometimes might write _header, *body2 = str2.split("\n") to convey the same message.


Here is a second way of doing that by treating the strings as comma-delimited CSV strings.

require 'csv'
arr1 = CSV.parse(str1)​
  #=> [["Category Name", "Code", "Enabled?", "Category Hidden?"],
  #    ["BUG", "BUG", "No", "No"],
  #    ["EXAMPLE 1", "EXAMPLE 1", "No", "No"],
  #    ["PRESENT", "PRESENT", "No", "No"]],

arr2 = CSV.parse(str2)
  #=> [["Category Name", "Code", "Enabled?", "Category Hidden?"],
  #    ["BUG AVAILABLE", "BUG", "No", "No"],
  #    ["EXAMPLE 2", "EXAMPLE 2", "Yes", "No"],
  #    ["PRESENT AVAILABLE", "PRESENT AVAILABLE", "No", "No"]]

Then

str = CSV.generate do |csv|
  csv << arr1.shift
  arr2.shift
  until arr2.empty? do
    csv << arr1.shift
    csv << arr2.shift
  end
end
  #=> "Category Name,Code,Enabled?,Category Hidden?\nBUG,BUG,No,No\nBUG AVAILABLE,BUG,No,No\nEXAMPLE 1,EXAMPLE 1,No,No\nEXAMPLE 2,EXAMPLE 2,Yes,No\nPRESENT,PRESENT,No,No\nPRESENT AVAILABLE,PRESENT AVAILABLE,No,No\n"
puts str
Category Name,Code,Enabled?,Category Hidden?
BUG,BUG,No,No
BUG AVAILABLE,BUG,No,No
EXAMPLE 1,EXAMPLE 1,No,No
EXAMPLE 2,EXAMPLE 2,Yes,No
PRESENT,PRESENT,No,No
PRESENT AVAILABLE,PRESENT AVAILABLE,No,No
    

See CSV::parse and CSV::generate.


This can also be done without converting the strings to arrays, manipulating those arrays to form a single array and then converting the single array back to a string.

arr = [str1, str2]
str_indices = 0..str1.count("\n") 
arr_indices = 0..arr.size-1
idx_begin = Array.new(arr.size, 0)

puts str_indices.each_with_object("") do |i, str|
  arr_indices.each do |j|
    idx_end = arr[j].index(/(?:\n|\z)/, idx_begin[j])
     s = arr[j][idx_begin[j]..idx_end]
     s << "\n" unless s[-1] == "\n" || (i == str_indices.last && j == arr_indices.last)
     str << s unless i.zero? && j > 0
     idx_begin[j] = idx_end + 1
  end
end
Category Name,Code,Enabled?,Category Hidden?
BUG,BUG,No,No
BUG AVAILABLE,BUG,No,No
EXAMPLE 1,EXAMPLE 1,No,No
EXAMPLE 2,EXAMPLE 2,Yes,No
PRESENT,PRESENT,No,No
PRESENT AVAILABLE,PRESENT AVAILABLE,No,No

The regular expression /(?:\n|\z)/ matches a newline character (\n) or (|) the end of the string (\z).

See the form of String#index that takes an optional second argument that specifies the string index where the search is to begin.

Upvotes: 4

Related Questions