How to Increment/Decrement a Character in Ruby for All Possible Values

How do I increment/decrement a character in Ruby for all possible values?

Depending on what the possible values are, you can use String#next:

"\x0".next
# => "\u0001"

Or, to update an existing value:

c = "\x0"
c.next!

This may well not be what you want:

"z".next
# => "aa"

The simplest way I can think of to increment a character's underlying codepoint is this:

c = 'z'
c = c.ord.next.chr
# => "{"

Decrementing is slightly more complicated:

c = (c.ord - 1).chr
# => "z"

In both cases there's the assumption that you won't step outside of 0..255; you may need to add checks for that.

Rails before_create increment in alphabetical order

There is actually a pretty cool way to do this in Postgres by applying a computed default value to the column.

First we want to define a Postgres function that gives you a letter given an integer (1 = A, 26 = Z) so that we can get a letter given an ID.

class CreateIdToLetterFunction < ActiveRecord::Migration[5.2]
def up
execute <<-SQL
CREATE OR REPLACE FUNCTION id_to_letter(integer) RETURNS varchar
AS 'select chr(64 + $1)'
LANGUAGE SQL
IMMUTABLE
RETURNS NULL ON NULL INPUT;
SQL
end

def down
execute <<-SQL
DROP FUNCTION id_to_letter(integer);
SQL
end
end

chr(int) returns the character with the given ASCII code. In ASCII A is at 65 so we need to pad the value with 64.

We then add function that counts the exposures so that we can use it the default:

class AddExposureCountFunction < ActiveRecord::Migration[5.2]
def up
execute <<-SQL
CREATE OR REPLACE FUNCTION count_exposures() RETURNS bigint
AS 'select count(*) from exposures'
LANGUAGE SQL
VOLATILE;
SQL
end

def down
execute <<-SQL
DROP FUNCTION count_exposures();
SQL
end
end

We then want to alter the exposures.setup_code column to add a default value.

class AddDefaultSetupCodeToExposures < ActiveRecord::Migration[5.2]
def change
change_column_default(
:exposures,
:setup_code,
from: nil,
to: -> {"id_to_letter(CAST(count_exposures() AS integer) + 1)"}
)
end
end

We wrap the new default in a lambda (->{}) as this tells ActiveRecord that the value is not a literal value and should be added to the statement as SQL.

As this is handled on the DB level no additional model code is needed. Note that the caveat regarding default values set by the DB applies - the value will be nil until you reload the instance from the db.

added

However if you want something functionally equal to the epically bad code from your comment you just need:

class Exposure < ApplicationRecord
SETUP_CODES = %w{ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z A2 B2 C2 D2 E2 F2 G2 H2 }
def self.next_setup_code(current_code)
if !SETUP_CODES.index(current_code) || current_code == SETUP_CODES.last
"error"
else
SETUP_CODES[ SETUP_CODES.index(current_code) + 1 ]
end
end
end

Ruby converting letters in string to letters 13 places further in the alphabet

From here -> How do I increment/decrement a character in Ruby for all possible values?

you should do it like:

def increment_char(char)
return 'a' if char == 'z'
char.ord.next.chr
end

def increment_by_13(str)
conc = []
tmp = ''
str.split('').each do |c|
tmp = c
13.times.map{ |i| tmp = increment_char(tmp) }
conc << tmp
end
conc
end

Or close.

Ruby how to increment a string number

You can convert that string to integer, call #next and then convert it back to string

'-3'.to_i.next.to_s

Does Ruby/Rails have a ++ equivalent?

Try this:

x += 1

Just for fun, how do I write a ruby program that slowly prints to stdout one character at a time?

Two things:

  1. You need to use .each_char to iterate over the characters. In Ruby 1.8, String.each will go line-by-line. In Ruby 1.9, String.each is deprecated.
  2. You should manually flush $stdout if you want the chars to appear immediately. Otherwise, they tend to get buffered so that the characters appear all at once at the end.

.

#!/usr/bin/env ruby
"a b c d d e f g h i j k".each_char {|c| putc c ; sleep 0.25; $stdout.flush }

How to write negative loop in ruby like for(i=index; i = 0; i --)

There are many ways to perform a decrementing loop in Ruby:

First way:

for i in (10).downto(0)
puts i
end

Second way:

(10).downto(0) do |i|
puts i
end

Third way:

i=10;
until i<0
puts i
i-=1
end

Increment variable in ruby

From the documentation,

Ruby has no pre/post increment/decrement operator. For instance, x++ or x-- will fail to parse

So, you can do

i += 1

which is equivalent of i = i + 1

How to update a counter or multiple counters in a single transaction?

you could use update_counters

User.update_counters(user_id, :sales_count => 1, :friend_count => 3, :other_count => -2)


Related Topics



Leave a reply



Submit