Help writing a each_unique method

I have this method:

  def each_unique_pair
    self.each_with_index{ |a,i|
      self[(i+1)..-1].each{ |b| yield a,b }
    }
  end

I'm trying to write a generalized version but having a bit of time about it:

  def each_unique(n=2)
    # how?
  end

My (imperfect) solutions keep leading me to recursion but I'd rather avoid it
(as I think it would be less efficient, correct me if I'm wrong)

Thanks,
T.

P.S. Does anyone have a really good String#word_wrap method? I wrote one but
it isn't so good b/c it strip newlines.

"trans. (T. Onoma)" <transami@runbox.com> schrieb im Newsbeitrag
news:200412131012.46675.transami@runbox.com...

P.S. Does anyone have a really good String#word_wrap method? I wrote one

but

it isn't so good b/c it strip newlines.

What about

class String
  def word_wrap!(n = 80)
    raise ArgumentError, "Wrap margin too low: #{n}" if n <= 2
    gsub!( Regexp.new( "(.{1,#{n-1}}\\w)\\b\\s*" ), "\\1\n")
  end

  def word_wrap(n = 80)
    c = dup
    c.word_wrap! n
    c
  end
end

Kind regards

    robert

One way:

  class Array
    def each_combination(k)
      n = self.size
      return unless (1..n) === k
      idx = (0...k).to_a
      loop do
        yield self.values_at(*idx)
        i = k - 1
        i -= 1 while idx[i] == n - k + i
        break if i < 0
        idx[i] += 1
        (i + 1 ... k).each {|j| idx[j] = idx[i] + j - i}
      end
    end
  end

  a = %w|a b c d e|
  n = 3
  a.each_combination(3) do |c|
    p c
  end

regards,
andrew

···

On Tue, 14 Dec 2004 00:12:50 +0900, trans. (T. Onoma) <transami@runbox.com> wrote:

I have this method:

  def each_unique_pair
    self.each_with_index{ |a,i|
      self[(i+1)..-1].each{ |b| yield a,b }
    }
  end

I'm trying to write a generalized version but having a bit of time about it:

  def each_unique(n=2)
    # how?
  end

My (imperfect) solutions keep leading me to recursion but I'd rather avoid it
(as I think it would be less efficient, correct me if I'm wrong)

require 'text/format'

Gavin

···

On Tuesday, December 14, 2004, 2:12:50 AM, trans. wrote:

P.S. Does anyone have a really good String#word_wrap method? I wrote one but
it isn't so good b/c it strip newlines.

Thanks, robert. That's a nice basic approach, and for the lack of something
better I think I will used. But it would be nice to have something a little
more robust. Something that can determine when to divide and hyphenate a word
if it is just too long.

Like I said, mine is far from perfect but I'll show it anyway:

  def word_wrap(max_width=nil, margin=6)
    max_width ||= 80
    max_width -= 1
    min_width = max_width - margin
    blocks = ; scan(/(.*)(\n\s+\n|\Z)/m){ blocks << $~ }
    complete = ''
    blocks.each{ |block|
      str = ''; line = ''
      body = block[1].gsub(/\s+/, ' ')
      padding = block[2].to_s
      words = body.split(/\s+/)
      i = 0
      words.each { |word|
        line << word
        while line.length > max_width
          clean_break = line.index(/\s\S*?$/)
          clean_break = 0 unless clean_break
          if clean_break < min_width
            remaining = line[max_width..-1]
            str << line.slice(0,max_width)
            str << '-' if /^[a-zA-Z0-9]/ =~ remaining
            str << "\n"
            line = line[max_width..-1]
          else
            str << line.slice(0,clean_break)
            str << " \n"
            line = line[(clean_break + 1)..-1]
          end
        end
        line << ' '
      }
      str << line.chomp(' ')
      complete << str << padding
    }
    complete << "\n"
  end

I never realized how complex something seemingly so simple could be.

Thanks,
T.

···

On Monday 13 December 2004 10:37 am, Robert Klemme wrote:

What about

class String
  def word_wrap!(n = 80)
    raise ArgumentError, "Wrap margin too low: #{n}" if n <= 2
    gsub!( Regexp.new( "(.{1,#{n-1}}\\w)\\b\\s*" ), "\\1\n")
  end

  def word_wrap(n = 80)
    c = dup
    c.word_wrap! n
    c
  end
end

Perfect. Thanks. Think #each_combination is best name?

T.

···

On Monday 13 December 2004 04:12 pm, Andrew Johnson wrote:

One way:

  class Array
    def each_combination(k)
      n = self.size
      return unless (1..n) === k
      idx = (0...k).to_a
      loop do
        yield self.values_at(*idx)
        i = k - 1
        i -= 1 while idx[i] == n - k + i
        break if i < 0
        idx[i] += 1
        (i + 1 ... k).each {|j| idx[j] = idx[i] + j - i}
      end
    end
  end

  a = %w|a b c d e|
  n = 3
  a.each_combination(3) do |c|
    p c
  end

Hi --

···

On Tue, 14 Dec 2004, trans. (T. Onoma) wrote:

On Monday 13 December 2004 10:37 am, Robert Klemme wrote:
> What about
>
> class String
> def word_wrap!(n = 80)
> raise ArgumentError, "Wrap margin too low: #{n}" if n <= 2
> gsub!( Regexp.new( "(.{1,#{n-1}}\\w)\\b\\s*" ), "\\1\n")
> end
>
> def word_wrap(n = 80)
> c = dup
> c.word_wrap! n
> c
> end
> end

Thanks, robert. That's a nice basic approach, and for the lack of something
better I think I will used. But it would be nice to have something a little
more robust. Something that can determine when to divide and hyphenate a word
if it is just too long.

Austin Ziegler is working on an interface to TeX's hyphenation
facilities. I'm not sure where it stands, but we were talking about
it last week and it sounded cool.

David

--
David A. Black
dblack@wobblini.net

"trans. (T. Onoma)" <transami@runbox.com> schrieb im Newsbeitrag news:200412131056.58363.transami@runbox.com...

> What about
>
> class String
> def word_wrap!(n = 80)
> raise ArgumentError, "Wrap margin too low: #{n}" if n <= 2
> gsub!( Regexp.new( "(.{1,#{n-1}}\\w)\\b\\s*" ), "\\1\n")
> end
>
> def word_wrap(n = 80)
> c = dup
> c.word_wrap! n
> c
> end
> end

Thanks, robert.

You're welcome.

That's a nice basic approach, and for the lack of something
better I think I will used. But it would be nice to have something a little
more robust. Something that can determine when to divide and hyphenate a word
if it is just too long.

Err, that plays in a whole different league...

Like I said, mine is far from perfect but I'll show it anyway:

def word_wrap(max_width=nil, margin=6)
   max_width ||= 80
   max_width -= 1
   min_width = max_width - margin
   blocks = ; scan(/(.*)(\n\s+\n|\Z)/m){ blocks << $~ }
   complete = ''
   blocks.each{ |block|
     str = ''; line = ''
     body = block[1].gsub(/\s+/, ' ')
     padding = block[2].to_s
     words = body.split(/\s+/)
     i = 0
     words.each { |word|
       line << word
       while line.length > max_width
         clean_break = line.index(/\s\S*?$/)
         clean_break = 0 unless clean_break
         if clean_break < min_width
           remaining = line[max_width..-1]
           str << line.slice(0,max_width)
           str << '-' if /^[a-zA-Z0-9]/ =~ remaining
           str << "\n"
           line = line[max_width..-1]
         else
           str << line.slice(0,clean_break)
           str << " \n"
           line = line[(clean_break + 1)..-1]
         end
       end
       line << ' '
     }
     str << line.chomp(' ')
     complete << str << padding
   }
   complete << "\n"
end

Ah, you use a margin to determine min line length. That makes things a bit more complicated of course. :slight_smile:

I never realized how complex something seemingly so simple could be.

I guess, that's because of the complexity of our language (no, not Ruby).

Kind regards

    robert

···

On Monday 13 December 2004 10:37 am, Robert Klemme wrote:

Minor correction. TeX::Hyphen already does this, but it only works
with English hyphenation and standard "czech" substitution. I would
not trust it with any other language, which is why I'm working on
Text::Hyphen. Martin DeMello ported TeX::Hyphen from the Perl
version and it works incredibly well.

Text::Format can use TeX::Hyphen as a plugin, so formatting can
happen with hyphenation.

I am in the process of reworking the architecture of TeX::Hyphen
(the algorithm is not going to change; this simply WORKS!) and it
will better support a wide variety of languages. I have converted 16
of 42 TeX hyphenation files to the new Text::Hyphen format that will
be used for languages. After I finish Text::Hyphen (this weekend?) I
will be revisiting Text::Format. Because I am changing the
initialization API with no backwards compatibility, I will be
renaming Text::Format to Text::Formatter and bumping the version to
1.0. After this, I will be working on Ruwiki and Diff::LCS again,
but I will be open to new features for Text::Formatter.

The algorithm behind Text::Formatter is extgensive; I highly
recommend using this instead of trying to write your own.

-austin

···

On Tue, 14 Dec 2004 01:05:45 +0900, David A. Black <dblack@wobblini.net> wrote:

On Tue, 14 Dec 2004, trans. (T. Onoma) wrote:

On Monday 13 December 2004 10:37 am, Robert Klemme wrote:

What about

class String
  def word_wrap!(n = 80)
    raise ArgumentError, "Wrap margin too low: #{n}" if n <= 2
    gsub!( Regexp.new( "(.{1,#{n-1}}\\w)\\b\\s*" ), "\\1\n")
  end

  def word_wrap(n = 80)
    c = dup
    c.word_wrap! n
    c
  end
end

Thanks, robert. That's a nice basic approach, and for the lack of
something better I think I will used. But it would be nice to
have something a little more robust. Something that can determine
when to divide and hyphenate a word if it is just too long.

Austin Ziegler is working on an interface to TeX's hyphenation
facilities. I'm not sure where it stands, but we were talking
about it last week and it sounded cool.

--
Austin Ziegler * halostatue@gmail.com
               * Alternate: austin@halostatue.ca