From: Christopher Swasey Date: 2008-03-03T16:20:51+09:00 Subject: Re: Split the string On 3/3/08, Sijo Kg wrote: > Here what is the meaning of this > > > t[0..1].map(&:to_i) << t[2] > > > Could u please explain details what split and map does?I am beginner in > ruby and ror The code, for reference: arr = "3:43;SD,2:65;SD,3:50;Inc".split(/,/).map do |i| t = i.split(/:|;/) t[0..1].map(&:to_i) << t[2] end First, what we're doing here is splitting the string into an array by the commas. This gets us => ["3:43;SD", "2:65;SD", "3:50;Inc"] Then we're iterating through the resulting array using #map. #map is provided by Enumerable. It iterates through all the elements of a collection and combines the results into a new array. #map passes each element to a block, one at a time. So, the first element that gets passsed to the block is the string "3:43;SD". What's important about the block is that the last expression to be evaluated gets returned, and #map will add the returned value onto the array that it's building. Inside the block we can do whatever we need to to build the returned value. In this case, we want the returned value to be a second array with the individual parts of the current string split up. If it didn't matter whether or not the resulting values were strings or integers then we could just call #split on the string and leave it at that, as "3:43;SD".split(/:\;/) returns => ["3", "43", "SD"] which, as the last expression evaluated, would get returned by the block and pushed onto the array being built by #map. You can think of #map as a function that transforms a collection, item by item, and gives you back a new collection of the same size with the same transformation applied to each constituent element. In this case, we're taking an array of strings, transforming each individual string into its own array, and we end up with an array of arrays. => [["3", "43", "SD"], ["2", "65", "SD"], ["3", "50", "Inc"]] Now, in this case all we've done is split a bunch of strings, so each ultimate element of the array is still going to be a string, even when they appear to be numbers and we want them to be integers. Ideally, what we'd do is a nested #map that called #to_i on each element to convert them to integers: i.split(/:|;/).map { |j| j.to_i } The problem is that we want the third element to remain a string. Calling #to_i on "SD" will return => 0 Which brings us to t[0..1].map(&:to_i) << t[2] What this does is slice out the first two elements of the array that the #split gave us. This results in an array. In this case t[0..1] would give us => ["3", "43"] Then we're mapping that to a new array by calling to_i on each element => [3, 43] Finally, we're pushing the string that we want to keep ("SD") onto the end [3, 43] << t[2] => [3, 43, "SD"] As the last expression to be evaluated, that completed array is returned to #map and gets pushed onto the final, resulting array. Now, I kind of skipped over a bit of code. t[0..1].map(&:to_i) << t[2] Specifically, the "&:to_i" part. This is somewhat advanced, and I'd suggest that you read up on blocks and Procs ASAP. This is a good opportunity to do so. Such knowledge is a prerequisite to understanding Symbol#to_proc. (Symbol#to_proc, btw, isn't part of Ruby core, it's a feature of Rails, although not exclusively). To put it in simple terms, prepending & to a symbol results in #to_proc being called on that symbol. #to_proc returns a simple block which accepts an object and calls the specified method. In this case, [].map(&:to_i) is the equivalent of [].map { |i| i.to_i } Again, it's very simple and neat and efficient if you understand how all the pieces of Ruby link together to make it possible. Once you read up on Procs and blocks it should make sense. Christopher