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
Rails: Violates Foreign Key Constraint
Heroku: How to Push to Specific App If You Have Multiple Apps in Heroku
Call Before Methods in Model on Ruby
Rails: Undefined Method 'Truncate' in Model
Semifixed: Missing 'Secret_Key_Base' for 'Production' Environment
Get an Array from a Rails Form
Ransack, Postgres - Sort on Column from Associated Table with Distinct: True
What Is the Purpose of Redo and Retry Statements in Ruby
Recovering from a Broken Tcp Socket in Ruby When in Gets()
How to Scrape Pages Which Have Lazy Loading
Rails 3.2.8 - How to Get the Week Number from Rails
Array Typeerror: Can't Convert Fixnum into String
Documentation for Psych To_Yaml Options
How to Do "Late" String Interpolation in Ruby