Building a String from Parts

Problem

You want to iterate over a data structure, building a string from it as you do.

Solution

There are two efficient solutions. The simplest solution is to start with an empty string, and repeatedly append substrings onto it with the << operator:

	hash = { "key1" => "val1", "key2" => "val2" }
	string = ""
	hash.each { |k,v| string << "#{k} is #{v}
" }
	puts string
	# key1 is val1
	# key2 is val2

This variant of the simple solution is slightly more efficient, but harder to read:

	string = ""
	hash.each { |k,v| string << k << " is " << v << "
" }

If your data structure is an array, or easily transformed into an array, it's usually more efficient to use Array#join:

	puts hash.keys.join("
") + "
"
	# key1
	# key2

 

Discussion

In languages like Python and Java, it's very inefficient to build a string by starting with an empty string and adding each substring onto the end. In those languages, strings are immutable, so adding one string to another builds an entirely new string. Doing this multiple times creates a huge number of intermediary strings, each of which is only used as a stepping stone to the next string. This wastes time and memory.

In those languages, the most efficient way to build a string is always to put the substrings into an array or another mutable data structure, one that expands dynamically rather than by implicitly creating entirely new objects. Once you're done processing the substrings, you get a single string with the equivalent of Ruby's Array#join. In Java, this is the purpose of the StringBuffer class.

In Ruby, though, strings are just as mutable as arrays. Just like arrays, they can expand as needed, without using much time or memory. The fastest solution to this problem in Ruby is usually to forgo a holding array and tack the substrings directly onto a base string. Sometimes using Array#join is faster, but it's usually pretty close, and the << construction is generally easier to understand.

If efficiency is important to you, don't build a new string when you can append items onto an existing string. Constructs like str << 'a' + 'b' or str << "#{var1} #{var2}" create new strings that are immediately subsumed into the larger string. This is exactly what you're trying to avoid. Use str << var1 <<''<< var2 instead.

On the other hand, you shouldn't modify strings that aren't yours. Sometimes safety requires that you create a new string. When you define a method that takes a string as an argument, you shouldn't modify that string by appending other strings onto it, unless that's really the point of the method (and unless the method's name ends in an exclamation point, so that callers know it modifies objects in place).

Another caveat: Array#join does not work precisely the same way as repeated appends to a string. Array#join accepts a separator string that it inserts between every two elements of the array. Unlike a simple string- building iteration over an array, it will not insert the separator string after the last element in the array. This example illustrates the difference:

	data = ['1', '2', '3']
	s = ''
	data.each { |x| s << x << ' and a '}
	s # => "1 and a 2 and a 3 and a "
	data.join(' and a ') # => "1 and a 2 and a 3"

To simulate the behavior of Array#join across an iteration, you can use Enumerable#each_with_index and omit the separator on the last index. This only works if you know how long the Enumerable is going to be:

	s = ""
	data.each_with_index { |x, i| s << x; s << "|" if i < data.length-1 }
	s # => "1|2|3"


Strings

Numbers

Date and Time

Arrays

Hashes

Files and Directories

Code Blocks and Iteration

Objects and Classes8

Modules and Namespaces

Reflection and Metaprogramming

XML and HTML

Graphics and Other File Formats

Databases and Persistence

Internet Services

Web Development Ruby on Rails

Web Services and Distributed Programming

Testing, Debugging, Optimizing, and Documenting

Packaging and Distributing Software

Automating Tasks with Rake

Multitasking and Multithreading

User Interface

Extending Ruby with Other Languages

System Administration



Ruby Cookbook
Ruby Cookbook (Cookbooks (OReilly))
ISBN: 0596523696
EAN: 2147483647
Year: N/A
Pages: 399

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net