Create a Human-Readable List with "And" Inserted Before the Last Element from a Ruby List

Create a human-readable list with and inserted before the last element from a ruby list

Try: [list[0...-1].join(", "), list.last].join(", and ").

Edit: Rails has the method you were probably looking for, called to_sentence.

In case you do not have Rails or do not wish to depend on Rails, open Array class and include the above method, like:

class Array
def join_all(join_with = ", ", connector = "and", last_comma = false)
return self.to_s if self.empty? || self.size==1
connector = join_with+connector if last_comma
[list[0...-1].join(join_with), list.last].join(connector)
end
end

Elegant way of joining names (',' and 'and') with Ruby

If you are using Rails, you could use the to_sentence method.

%(alex bob charles).to_sentence would give you alex, bob and charles.

That method is defined here: activesupport/lib/active_support/core_ext/array/conversions.rb

How do I convert an array of strings into a comma-separated string?

["10", "20", "50","99"].map(&:inspect).join(', ') # => '"10", "20", "50", "99"'

How to turn an array of strings into a list with an oxford comma using array methods in Ruby

When you have just one element in the array, Array#join returns the element itself:

['a'].join(' and ') #=> "a"

So, you could simplify your code prepending "and " to the last element when list size is 3 or more or returning .join(' and ') if less than 3 elements:

def oxford_comma(list)
return list.join(' and ') if list.size < 3
list[-1] = "and " + list[-1]
list.join(', ')
end

Array to String with specific format

You can use the splat operator to split the array and just check the case if there's only one string:

def message(constraints)
*others, second_last, last = constraints[:contain]
second_last += " and #{last}" unless last.nil?
"#{constraints[:length]} Must contain: #{(others << second_last).join(', ')}"
end

@password_constraints = {
length: 'Must be at least 6 character long.',
contain: [
'one number',
'one lowercase letter',
'one uppercase letter.'
]
}

message(@password_constraints)
# => "Must be at least 6 character long. Must contain: one number, one lowercase letter and one uppercase letter."

# if @password_constraints[:contain] = ['one lowercase letter', 'one uppercase letter.']
message(@password_constraints)
# => "Must be at least 6 character long. Must contain: one lowercase letter and one uppercase letter."

# if @password_constraints[:contain] = ['one lowercase letter']
message(@password_constraints)
# => "Must be at least 6 character long. Must contain: one lowercase letter"

How does .insert work?

I'm not sure what the confusion is. From the Ruby docs:

ary.insert(index, obj...)  -> ary

Inserts the given values before the element with the given index (which may be
negative).

a = %w{ a b c d }
a.insert(2, 99) #=> ["a", "b", 99, "c", "d"]
a.insert(-2, 1, 2, 3) #=> ["a", "b", 99, "c", 1, 2, 3, "d"]

So, a.insert(2, 99) is inserting 99 into the array just before array offset 2. Remember that an array's index starts at 0, so that is the third slot in the array.

The second example is inserting the array [1,2,3] into the second-from-the-last array slot, because negative offsets count from the end of the array. -1 is the last index, -2 is the second to last.

The Array docs say it well:

Array indexing
starts at 0, as in C or Java. A negative index is assumed to be relative to
the end of the array---that is, an index of -1 indicates the last element of
the array, -2 is the next to last element in the array, and so on.

These are VERY important concepts to learn in programming in general, not just in Ruby.

Reposition an element to the front of an array in Ruby

This is a trickier problem than it seems. I defined the following tests:

describe Array do
describe '.promote' do
subject(:array) { [1, 2, 3] }

it { expect(array.promote(2)).to eq [2, 1, 3] }
it { expect(array.promote(3)).to eq [3, 1, 2] }
it { expect(array.promote(4)).to eq [1, 2, 3] }
it { expect((array + array).promote(2)).to eq [2, 1, 3, 1, 2, 3] }
end
end

sort_by proposed by @Duopixel is elegant but produces [3, 2, 1] for the second test.

class Array
def promote(promoted_element)
sort_by { |element| element == promoted_element ? 0 : 1 }
end
end

@tadman uses delete, but this deletes all matching elements, so the output of the fourth test is [2, 1, 3, 1, 3].

class Array
def promote(promoted_element)
if (found = delete(promoted_element))
unshift(found)
end

self
end
end

I tried using:

class Array
def promote(promoted_element)
return self unless (found = delete_at(find_index(promoted_element)))
unshift(found)
end
end

But that failed the third test because delete_at can't handle nil. Finally, I settled on:

class Array
def promote(promoted_element)
return self unless (found_index = find_index(promoted_element))
unshift(delete_at(found_index))
end
end

Who knew a simple idea like promote could be so tricky?

Adding values to array hash ruby at a specific position

We are given three objects.

jsonResponse = {
:json=>{
"reply"=>[
{"person"=>"abc", "roll_no"=>"1234", "location"=>"loc1", "score"=>"1"},
{"person"=>"def", "roll_no"=>"1235", "location"=>"loc2", "score"=>"2"},
{"person"=>"fgh", "roll_no"=>"1236", "location"=>"loc3", "score"=>"3"}
]
},
:status=>200
}

key_value_pair_to_add = { 'new_value'=>'new_result' }
key_to_precede = 'location'

We then modify jsonResponse as follows.

keys_to_shift = jsonResponse[:json]['reply'][0].keys.
drop_while { |k| k != key_to_precede }
#=> ["location", "score"]
jsonResponse[:json]['reply'].each do |h|
h.update('new_value'=>'new_result')
keys_to_shift.each { |k| h.update(k=>h.delete(k)) }
end
jsonResponse
#=> {
# :json=>{
# "reply"=>[
# {"person"=>"abc", "roll_no"=>"1234", "new_value"=>"new_result",
# "location"=>"loc1", "score"=>"1"},
# {"person"=>"def", "roll_no"=>"1235", "new_value"=>"new_result",
# "location"=>"loc2", "score"=>"2"},
# {"person"=>"fgh", "roll_no"=>"1236", "new_value"=>"new_result",
# "location"=>"loc3", "score"=>"3"}
# ]
# },
# :status=>200
# }

See Hash#update (aka merge!) and Hash#delete.

h.delete('location')

removes the key-value pair 'location'=>'locX' from h and returns locX, after which

h.update('location'=>'locX')

returns that key-value pair to the end of the hash. This is repeated for each key in keys_to_shift.



Related Topics



Leave a reply



Submit