Fork me on GitHub

Project Notes

#377 Split by Widths

Using ruby to split strings into chunks of specified widths; cassidoo’s interview question of the week (2025-10-20).

Notes

The interview question of the week (2025-10-20) should play to ruby’s strength and flexibility in array and string processing:

Given a string str and an array of positive integers widths, write a function that splits the string into lines, each with the exact number of characters as specified by the corresponding width. Return an array of the substrings. Use the last width for any remaining characters if the array is shorter than needed.

Example:

const str = "Supercalifragilisticexpialidocious";
const widths = [5, 9, 4];

> splitByWidths(str, widths);
> ['Super', 'califragi', 'list', 'icex', 'pial', 'idoc', 'ious']

Thinking about the Problem

The widths array could be just right for the given string, or it could have a surfeit or excess of elements.

Similarly, the string may not exactly divide according to the widths. We basically need to keep processing until all characters are consumed.

A First Go

We take advantage of ruby’s forgiving nature in two places:

  • shift will return nil if we’ve run out of elements, so we keep the previous value as a fallback: width = widths.shift || width
  • and input[index, width] will return up to width characters, but not complain if it runs short
def split_by_widths(input, widths)
  result = []
  index = 0
  while index < input.length do
    width = widths.shift || width
    result << input[index, width]
    index += width
  end
  result
end

Running some examples:

$ ./example.rb "Supercalifragilisticexpialidocious" "5, 9, 4"
["Super", "califragi", "list", "icex", "pial", "idoc", "ious"]
$ ./example.rb "Supercalifragilisticexpialidocious" "5, 9, 6"
["Super", "califragi", "listic", "expial", "idocio", "us"]
$ ./example.rb "abcdefg" "1"
["a", "b", "c", "d", "e", "f", "g"]
$ ./example.rb "abcdefghij" "3, 2, 4, 6, 6"
["abc", "de", "fghi", "j"]

Tests

I’ve setup some validation in test_example.rb:

$ ./test_example.rb
Run options: --seed 29972

# Running:

....

Finished in 0.000229s, 17467.2489 runs/s, 17467.2489 assertions/s.

4 runs, 4 assertions, 0 failures, 0 errors, 0 skips

Example Code

Final code is in example.rb:

#!/usr/bin/env ruby

def split_by_widths(input, widths)
  result = []
  index = 0
  while index < input.length do
    width = widths.shift || width
    result << input[index, width]
    index += width
  end
  result
end

if __FILE__ == $PROGRAM_NAME
  (puts "Usage: ruby #{$0} (string) (widths comma separated)"; exit) unless ARGV.length > 1
  input = ARGV[0]
  widths = ARGV[1].split(',').map(&:to_i)
  puts split_by_widths(input, widths).inspect
end

Credits and References

About LCK#377 rubycassidoo

This page is a web-friendly rendering of my project notes shared in the LittleCodingKata GitHub repository.

Project Source on GitHub Return to the LittleCodingKata Catalog
About LittleCodingKata

LittleCodingKata is my collection of programming exercises, research and code toys broadly spanning things that relate to programming and software development (languages, frameworks and tools).

These range from the trivial to the complex and serious. Many are inspired by existing work and I'll note credits and references where applicable. The focus is quite scattered, as I variously work on things new and important in the moment, or go back to revisit things from the past.

This is primarily a personal collection for my own edification and learning, but anyone who stumbles by is welcome to borrow, steal or reference the work here. And if you spot errors or issues I'd really appreciate some feedback - create an issue, send me an email or even send a pull-request.

Follow the Blog follow projects and notes as they are published in your favourite feed reader