2
votes

I'm interested in possible ways that different languages can Join an array, but rather than using a single join string, using a different join string at given intervals.

For example (hypothetical language):

Array.modJoin([mod, char], ...)
e.g. [1,2,3,4,5].modJoin( [1, ","], [2, ":"] )

Where the arguments specify an array or object containing a modulo and a join char, the implementation would check which order of modulo took precedence (the latest one), and apply the join char. (requiring that the [mod,char]'s were provided in ascending mod order)

i.e.

if (index % (nth mod) == 0) 
  append (join char) 
  continue to next index 
else 
  (nth mod)-- repeat

when complete join with ""

For example, I've come up with the following in Ruby, but I suspect better / more elegant methods exist, and that's what I'd like to see.

#Create test Array 
#9472 - 9727 as HTML Entities (unicode box chars)
range       = (9472..9727).to_a.map{|u| "&##{u};" }  

Assuming we have a list of mod's and join chars, we have to stipulate that mods increase in value as the list progresses.

mod_joins   = [{m:1, c:",", m:12, c:"<br/>"]

Now process the range with mod_joins

processed = range.each_with_index.map { |e, i| 
  m = nil
  mods.reverse_each {|j|
    m = j and break if i % j[:m] == 0
  }
  # use the lowest mod for index 0
  m = mods[0] if i == 0 
  m = nil ? e : "#{e}#{m[:c]}"
}

#output the result string
puts processed.join ""

From this we have a list of htmlEntities, separated by , unless it's index is a 12th modulo in which case it's a <br/>

So, I'm interested for ways this can be done more elegantly, primarily in functional languages like Haskell, F#, Common Lisp (Scheme, Clojure) etc. but also cool ways to achieve this in general purpose languages that have list comprehension extensions such as C# with Linq, Ruby and Python or even Perl.

2

2 Answers

1
votes

Here's a pure-functional version written in Python. I'm sure it can be adapted easily enough to other languages.

import itertools

def calcsep(num, sepspecs):
  '''
    num: current character position
    sepspecs: dict containing modulus:separator entries
  '''
  mods = reversed(sorted(sepspecs))
  return sepspecs[next(x for x in mods if num % x == 0)]

vector = [str(x) for x in range(12)]

result = [y for ix, el in enumerate(vector)
            for y in (calcsep(ix, {1:'.', 3:',', 5:';'}), el)]

print ''.join(itertools.islice(result, 1, None))
1
votes

Here’s a simpler and more readable solution in Ruby

array = (9472..9727).map{|u|"&##{u};"}
array.each_slice(12).collect{|each|each.join(",")}.join("<br/>")

or for the general case

module Enumerable   
  def fancy_join(instructions)
    return self.join if instructions.empty?
    separator = instructions.delete(mod = instructions.keys.max)
    self.each_slice(mod).collect{|each|each.fancy_join(instructions.dup)}.join(separator)
  end
end

range = (9472..9727).map{|u|"&##{u};"}
instructions = {1=>",",12=>"<br/>"}

puts array.fancy_join(instructions)