Help writing a each_unique method

T

trans. (T. Onoma)

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.
 
R

Robert Klemme

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

trans. (T. Onoma)

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.
 
D

David A. Black

Hi --

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
 
R

Robert Klemme

trans. (T. Onoma) said:
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
 
A

Andrew Johnson

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 == n - k + i
break if i < 0
idx += 1
(i + 1 ... k).each {|j| idx[j] = idx + 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
 
T

trans. (T. Onoma)

|
| 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 == n - k + i
| break if i < 0
| idx += 1
| (i + 1 ... k).each {|j| idx[j] = idx + 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.
 
A

Austin Ziegler

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,164
Messages
2,570,901
Members
47,439
Latest member
elif2sghost

Latest Threads

Top