Re: Modifying a hash key
On Sep 17, 12:53 pm, "Robert Klemme" <shortcut...@googlemail.com>
wrote:
>
> > So the real answer to my question (what is the reason for hash to
> > store it's keys by reference?) might be: trading rule of a thumb for
> > speed and memory?
>
> No, the reason is that you can only store by reference in Ruby (there
> are some internal optimizations for Fixnum and the like but the code
> still basically behaves the same).
Yes, but hash implementation could make a copy of the key when it
inserts new elements. Of course, this will slow down the code in
significant part of programs, so there is the trade-off I've talked
about. :-)
> > state={}
> > prefix=[]
> > while $stdin.eof?
>
> Are you serious about the line above? I'd rather have expected "until" there.
Sorry, of course not. It was pulled off the top of my head, since no
real code was at hand (I've posted that from work, and the Ruby code
is something I keep at home (-: ).
> I'd do this, note all the freezing in order to make errors with
> changing keys obvious.
>
> state = Hash.new {|h,k| h[k]=[]}
> prefix = [].freeze
>
> ARGF.each do |line|
> line.scan /\w+/ do |word|
> state[prefix] << word.freeze
> (prefix += [word]).freeze
> # or: prefix = (prefix.dup << word).freeze
> end
> end
Uh-oh... this freeze stuff seems overly complicated to me.
> Btw, there's probably a more efficient way of storing this if you
> introduce a specialized class for prefix chaining. Probably like
> this:
>
> Prefix = Struct.new :word, :previous
>
> > w=... # read a word
> > state[prefix] << w
> > ...
> > prefix << w # <-- Bang! The hash key is changed... :-)
>
> You can #dup the prefix or use +:
> prefix += [w]
My real code is as follows:
require 'scanf'
NPREFIX = 2
$nwords = ARGV[0] ? ARGV[0].to_i() : 1000
#
# acquire knowledge
#
state = {}
prefix = []
while not $stdin.eof? do
# w, = scanf("%s")
words = $stdin.gets().scan(/[^\s]+/)
words.each do |w|
suf = state[prefix]
if not suf
suf = state[prefix.clone()] = []
end
suf << w
if prefix.length >= NPREFIX
prefix.shift
end
prefix << w
end
end
state[prefix] = []
#
# generate pseudo-text
#
prefix = []
count = 0
while count < $nwords do
suf = state[prefix]
if suf.empty?
break
end
w = suf[rand(suf.length)]
print w + " "
if prefix.length >= NPREFIX
prefix.shift
end
prefix << w
count += 1
end
puts
May be an eye of experienced programmer could catch some more odd
places in my code? See, I'm just a Ruby newbie... Please do not
waste more of your time than really necessary on this. :-)
Cheers,
Alex
|