hoodwink.d enhanced
RSS
2.0
XHTML
1.0

RedHanded

ary / 3 #

by why in bits

Sometimes I wish Array.partition could split into more than halves. Something like partition_by or commonality. Like an Array./ method!

 class Array
   def / len
     inject([]) do |ary, x|
       ary << [] if [*ary.last].nitems % len == 0
       ary.last << x
       ary
     end
   end
 end

 >> products = %w[cycles vents hoops willies moogs rifles pools fawns tridents]
 >> products / 3
 => [["cycles", "vents", "hoops"], ["willies", "moogs", "rifles"], 
     ["pools", "fawns", "tridents"]]
 >> products / 2
 => [["cycles", "vents"], ["hoops", "willies"], 
     ["moogs", "rifles"], ["pools", "fawns"], ["tridents"]]

The other alternative being a hopscotch with a flip-flop.

said on

This should be faster (didn’t try it):


require 'enumerator'
class Array
  def /(len); enum_for(:each_slice,len).to_a end 
end

Actually it’s not Array.partition but Enumerable#partition, so you could define it there (given a better name).

said on
class Array def / len each_index{|i| self[(i + 1)...(i + len)] = self[i+len] } end end
said on

Is this the same as each_slice ?

Granted, the source isn’t quite as compact.

each_slice(step=nil, &yld) Iterate through slices. If slicing step is not given, the the arity if the block is used.
  
  x = []
  [1,2,3,4].each_slice(2){ |a,b| x << [a,b] }
  x  #=> [ [1,2], [3,4] ]

  x = []
  [1,2,3,4,5,6].each_slice(3){ |a| x << a }
  x  #=> [ [1,2,3], [4,5,6] ]

said on

yxhuvud: Super sly, but that method needs a bang.

scili: Ohhh, using the arity of the block is a wise idea! Geez, Facets is an entire schoolhouse of fledgling RCRs.

said on

each_slice is writen in a peculairly inefficient way, unless I’m mistaken, also… am I crazy or does the first example need to drop the parameter 2 to demonstrate the behavior when step isn’t supplied?

My fixed(?) version:
  def each_slice(step=nil, &yld)
    cnt = step || yld.arity.abs
    n = length / cnt
    n += 1 if length % cnt > 0
    n.times do |i|
      yld.call(*self.slice(i*cnt,cnt))
    end
    return cnt
  end

said on

Uh, scratch that, not inefficient, just very unDRY.

said on

ruby nube, but wouldn’t

class Array
  def / len
    inject([[]]) do |ary, x|
      ary << [] if ary.last.size >= self.size / len 
      ary.last << x
      ary
    end
  end
end

be more keeping with the idea of division?

said on

Aye, the functionality described in the post is useful, but it’s not what I’d expect from what looks like a division operator. I’d expect

products / 2

to return

[["cycles", "vents", "hoops", "willies", "moogs"], ["rifles", "pools", "fawns", "tridents"]]

said on

Maybe it should be called slice_by then?

said on

whichever the algo, or name. just thought that it should be noted that its important to be keeping those nils around. e.g. size() instead of nitems()

[1,2,nil,3,nil,nil,4,5,6] / 4 => [[1, 2, nil, 3], [nil, nil, 4, 5], [6]] => [[1, 2, 3, 4], [5, 6]]

/ 4
said on

oops. the examples was,

[1,2,nil,3,nil,nil,4,5,6] / 4 => [[1, 2, nil, 3], [nil, nil, 4, 5], [6]] <br><br> [1,2,nil,3,nil,nil,4,5,6].compact / 4 => [[1, 2, 3, 4], [5, 6]]
said on

Okay, so maybe mine should use the modulo then.

said on

i wrote some related but different code to cut up Ranges in to partitions of a known size: I called it Range.%

I think must have been half-asleep when I wrote the code, though, I looks sort of ugly:

class Range
  def %(q)
    q = 1 if q <= 0
    a = []

    i = self.end

    if(i == self.begin)
      return([self])
    end

    while(i > self.begin)
      lasti = i
      i -= q
    q = 1 if q.zero?
    a = []

    i = self.begin
    l = self.end
    l -= 1 if self.exclude_end?
    while(i <= self.end)
      lasti = i
      i += q
  if(l < i)
        if self.exclude_end?
          a.push(lasti...l)
        else
          a.push(lasti..l)
        end
      else
        a.push(lasti...i)
      end
    end
    return a
  end
end
irb(main):008:0> (1...100) % 10
=> [90...100, 80..90, 70..80, 60..70,
50..60, 40..50, 30..40, 20..30, 10..20,
1..10]
said on

Actually, Why, I would call your method % and have / divide your array into (n) parts of equal size

[1,2,3,4,5,6] / 2 => [[1,2,3], [4,5,6]] [1,2,3,4,5,6] % 2 => [[1,2], [3,4], [5,6]]
said on

nevermind that last comment, you’re already agreeing with me.

said on
.oO(Why are they all rewriting what enumerator already does and more efficiently at that)
said on

mfp: mmmmhm! hallelujah!(sic)

said on

I’ve been lurking in the Ruby/Rails commuity for a while, but I haven’t seen many references to ‘Facets’. Why? Is seems a suprememly useful library, but no one mentions it.

For example; I don’t find it pre-gemed (real noob here) on many sites that offer Ruby/Rails hosting.

Will I run into trouble if I install then depend on Facets?

Sorry for the distraction.

said on

n00bi3 – u could either ask them to add it for u (possibly offer them a nice chocolate cake as a reward) – they are usually quite friendly

or u could copy and paste the function(s) u need from the source code of the gem into ur project :-)

said on

My two cents: a = (1..10).to_a; maxsubarraysize = 3-1; result = []; while a.size > 0; result << a.slice!(0..maxsubarraysize); end

said on

”.oO(Why are they all rewriting what enumerator already does and more efficiently at that)”

shrug

Because we are ignorant.

cheers, prat

said on

noobish: You don’t see many references to Facets because Facets is … far too large for most people to want to use. There are sometimes other reasons, too.

I personally wouldn’t use any library that depended on Facets, because I vehemently disagree with most of the “design” decisions made in making the library.

said on
What about something like this?
# ---------------------------------------------------------------------------
# collect_every(n [,fill=false[,offset=0]])                  => an array
# collect_every(n [,fill=false[,offset=0]]) {|item| block}   => an_array
# ---------------------------------------------------------------------------
# If a block is given, it invokes the block passing in an array of n elements.
# The last array passed may not contain n elements if size % 2 does not equal
# zero. If no block is given, it returns an array containing the collections.
#
# If the optional argument fill is set to true, the empty spaces will be
# filled with nils. The optional argument offset allows the collection to 
# start at that index in the array.
#
# a = (1..10).to_a
# a.collect_every(5)               #=> [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
# a.collect_every(5) {|x| p x}     #=> [1, 2, 3, 4, 5]
#                                      [6, 7, 8, 9, 10]
# b = (1..7).to_a
# b.collect_every(3)               #=> [[1, 2, 3], [4, 5, 6], [7]]
# b.collect_every(3,true)          #=> [[1, 2, 3], [4, 5, 6], [7,nil,nil]]
# b.collect_every(3,true,1)        #=> [[2, 3, 4], [5, 6, 7]]

class Array
  def collect_every(n,fill=false,offset=0)

    if block_given?
      while offset < size
        ret=[]

        if fill
          n.times do |x| 
            if offset+x > size - 1: ret << nil
            else ret << self[offset+x] end
          end
        else
          n.times { |x| ret << self[offset+x] unless offset+x > size-1 }
        end

        offset += n
        yield ret
        ret = nil
      end

    else
      ret = []
      while offset < size
        ret << []

        if fill
          n.times do |x|
            if offset+x > size - 1: ret.last << nil
            else ret.last << self[offset+x] end
          end
        else
          n.times { |x| ret.last << self[offset+x] unless offset+x > size-1 }
        end

        offset += n
      end
      return ret
    end

  end
end
said on

Thanks JakDak, I know how to use gems. :-). I’m more interested in Austins answer. What design decisions did they make that turn you off?

said on

Ezra, this is the all-in-one solution! Nice!

said on

Why not “if offset+x > size – 1 THEN ret.last << nil; else ret.last … end”? Would be a bit easier to read, imho!

Comments are closed for this entry.