[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Help writing a each_unique method

T. Onoma

12/13/2004 3:13:00 PM

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.


8 Answers

Robert Klemme

12/13/2004 3:36:00 PM

0


"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

T. Onoma

12/13/2004 3:57:00 PM

0

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.

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.


dblack

12/13/2004 4:06:00 PM

0

Robert Klemme

12/13/2004 8:00:00 PM

0


"trans. (T. Onoma)" <transami@runbox.com> schrieb im Newsbeitrag
news:200412131056.58363.transami@runbox.com...
> 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.

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. :-)

> 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

Andrew Johnson

12/13/2004 9:11:00 PM

0

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)

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

Gavin Sinclair

12/13/2004 11:33:00 PM

0

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.

require 'text/format'

Gavin



T. Onoma

12/13/2004 11:56:00 PM

0

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

Perfect. Thanks. Think #each_combination is best name?

T.


Austin Ziegler

12/14/2004 2:55:00 AM

0

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.

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
--
Austin Ziegler * halostatue@gmail.com
* Alternate: austin@halostatue.ca