Skip to content

Instantly share code, notes, and snippets.

@tinomen
Created May 28, 2013 23:44
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tinomen/5666990 to your computer and use it in GitHub Desktop.
Save tinomen/5666990 to your computer and use it in GitHub Desktop.
<p>Using <a href="http://projecteuler.net/project/names.txt">names.txt</a> (right click and 'Save Link/Target As...'), a 46K text file containing over five-thousand first names,
begin by sorting it into alphabetical order. Then working out the alphabetical value for each name, multiply this value by
its alphabetical position in the list to obtain a name score.
</p>
<p>For example, when the list is sorted into alphabetical order, COLIN, which is worth 3 + 15 + 12 + 9 + 14 = 53, is the
938th name in the list. So, COLIN would obtain a score of 938 x 53 = 49714.
</p>
<p>What is the total of all the name scores in the file?</p>
@bmabey
Copy link

bmabey commented May 29, 2013

#!/usr/bin/env ruby

CODES = Hash[(?A..?Z).zip(1..26)]
def name_score(name, pos)
  name.chars.map{|c| CODES[c] }.reduce(&:+) * pos
end

require 'csv'
puts "Total: " +
  CSV.readlines("names.txt").first.sort.
  map.with_index{ |name, i| name_score(name, i+1)}.reduce(&:+).to_s

Total: 871198282

@dandorman
Copy link

#!/usr/bin/env ruby

file = File.read 'names.txt'

names = eval("[#{file}]")
scores = names.sort.each_with_index.inject({}) do |scores, (name, index)|
  scores[name] = name.chars.inject(0) { |sum, char| sum + char.ord - 64 } * (index + 1)
  scores
end

puts scores.values.inject(&:+) # => 871198282

@tinomen
Copy link
Author

tinomen commented May 29, 2013

#!/usr/bin/env ruby

LETTERS = %w{. A B C D E F G H I J K L M N O P Q R S T U V W X Y Z}

total = 0
File.read("names.txt").gsub(/"/,'').split(',').sort.each_with_index do |name, i|
  score = name.split('').inject(0){|sum, c| sum + LETTERS.index(c)}
  total += (score * (i+1))
end

puts total

Total: 871198282

@hamiltop
Copy link

Is there any purpose in sorting?

@aamax
Copy link

aamax commented May 29, 2013

describe "sort list by alpha" do
  # it "should read list of names from resource and sort" do
  #   data = ["john","sam", "fred", "suzie", "brandi", "george"]
  #   
  #   sort_list(data).should == ["brandi","fred","george","john","sam", "suzie"]
  # end

  it "should return a value for a list with a single name" do
    data = ["fred"]

    process_list(data).should == 33
  end
end

def process_list(data)
  @hash_key = {
    a: 1, b: 2, c: 3, d: 4,
    e: 5, f: 6, g: 7, h: 8,
    i: 9, j: 10, k: 11, l: 12,
    m: 13, n: 14, o: 15, p: 16,
    q: 17, r: 18, s: 19, t: 20,
    u: 21, v: 22, w: 23, x: 24, 
    y: 25, z: 26
  }
  total = 0
  data.each_with_index do |name, i|

    puts name

    name_total = 0
    name.split('').each do |letter|
      name_total += @hash_key[letter.to_sym]
    end
    total += (i + 1) * name_total
  end
  total
end

names = []
fname = "names.txt"
File.open(fname, "r") do |f|
  f.readlines.each do |line|
    line.gsub('"', '')
    names = line.chomp.split(',')
    names.sort!
  end
end
puts names

puts process_list(names)

@bmabey
Copy link

bmabey commented May 29, 2013

@hamiltop because the problem description tells you to :p

@tinomen
Copy link
Author

tinomen commented May 29, 2013

um, yeah. the problem calls for sorting the names

@bmabey
Copy link

bmabey commented May 29, 2013

Or I can save a few characters with several more lines of monkey patching!

CODES = Hash[(?A..?Z).zip(1..26)]

class Hash
  def to_proc
    proc { |v| self[v]}
  end
end

def name_score(name, pos)
  name.chars.map(&CODES).reduce(&:+) * pos
end

require 'csv'
puts "Total: " +
  CSV.readlines("names.txt").first.sort.
  map.with_index{ |name, i| name_score(name, i+1)}.reduce(&:+).to_s

Seriously though, Ruby should have a default Hash#to_proc.

@scizo
Copy link

scizo commented May 29, 2013

I'm shooting for esoteric

require 'csv'
compile_options = RubyVM::InstructionSequence.compile_option.merge(:tailcall_optimization => true)

iseq = RubyVM::InstructionSequence.compile <<SRC, nil, nil, nil, compile_options
CODES = Hash[(?A..?Z).zip(1..26)]

def name_score(pos, name, total=0)
  if name.empty?
    pos * total
  else
    name_score pos, name[1..-1], total + CODES[name[0]]
  end
end

def calc_total(names, pos=1, total=0)
  if names.empty?
    total
  else
    calc_total names[1..-1], pos + 1, total + name_score(pos, names[0])
  end
end

puts calc_total(CSV.open("names.txt").readline.sort)
SRC

iseq.eval

@hamiltop
Copy link

@tinomen I missed the "multiply by its alphabet position". Makes sense.

@dandorman
Copy link

@bmabey Hash#to_proc: I love it!

@scizo That is flat-out awesome.

@dbrady
Copy link

dbrady commented Jun 3, 2013

You guys are all nuts. ...I miss you. :-) I need to get out to urug more.

@dbrady
Copy link

dbrady commented Jun 3, 2013

Had I been there, here's my $0.02 of craziness to add to the pile: "proper" (IMO) monkeypatching and a nasty old C trick I used to use for converting letters to their decimal positions:

class Array
  def sum
    inject :+
  end
end

class String
  def letter_position
    self.ord ^ 64
  end

  def score
    each_char.map(&:letter_position).sum
  end

  def positional_score(position)
    position * score
  end
end

require 'csv'
puts CSV.readlines("names.txt").first.sort.map.
  with_index(1) {|name, index| name.positional_score index }.sum

...srsly, I need to get out to urug more. :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment