r/dailyprogrammer • 3 1 • May 14 '12

[5/14/2012] Challenge #52 [easy]

Imagine each letter and its position within the alphabet. Now assign each letter its corresponding value ie a=1, b=2,... z=26. When given a list of words, order the words by the sum of the values of the letters in their names.

Example: Shoe and Hat

Hat: 8+1+20 = 29

Shoe: 19+8+15+5 = 47

So the order would be Hat, Shoe.

For extra points, divide by the sum by the number of letters in that word and then rank them.

thanks to SpontaneousHam for the challenge at /r/dailyprogrammer_ideas .. link


Please note that [difficult] challenge has been changed since it was already asked

http://www.reddit.com/r/dailyprogrammer/comments/tmnfn/5142012_challenge_52_difficult/

fortunately, someone informed it very early :)

16 Upvotes

45 comments sorted by

4

u/SpontaneousHam May 14 '12

Hey, my challenge!

3

u/jonzo1 May 14 '12

Clojure:

(defn int-value
  [c]
  (- (Character/digit c 36) 9))

(defn compute-sum
  [word]
  (->> word (map int-value) (reduce +)))

(defn do-rank
  [& words]
  (sort-by compute-sum words))

3

u/ret0 May 14 '12

Python3:

def mytotal(word):
	return sum([ord(x)-96 for x in word.lower()])


def mysort(seq):
	return sorted(seq, key=mytotal)
→ More replies (3)

2

u/luxgladius May 14 '12

Perl

use List::Util qw/sum/;
use List::MoreUtils qw/zip/;
my @alph = 'a'..'z'; my @num = 1 .. 26;
my %map = zip(@alph, @num); my %val; my %avg;
while(<>) {
    $_ = lc;
    s/[^a-z]//g;
    $val{$_} = sum(map {$map{$_}} grep /[a-z]/, split //, lc);
    $avg{$_} = $val{$_} / length;
    print "$val{$_}, $avg{$_}\n";
}
for my $rank (\%val, \%avg) {
    print join(", ", sort {$rank->{$a} <=> $rank->{$b}} keys %$rank), "\n";
}

Output

perl dp52e.pl
hat
29, 9.66666666666667
shoe
47, 11.75
^Z
hat, shoe
hat, shoe

2

u/loonybean May 14 '12 edited May 14 '12

Javascript:

function orderWords(words) //words is an array of strings
{
	words.sort(function(a,b)
	{
		aScore = 0, bScore = 0, aLen = a.length, bLen = b.length;
		a = a.toLowerCase(), b = b.toUpperCase();
		for(var i=0;i<aLen || i<bLen;i++)
		{
			aScore += i < aLen ? a.charCodeAt(i) - 64 : 0;
			bScore += i < bLen ? b.charCodeAt(i) - 64 : 0;
		}
		return aScore - bScore;
	});
	return words;
}

The answer to the bonus question is hardly any different:

function orderWords(words) //words is an array of strings
{
	words.sort(function(a,b)
	{
		aScore = 0, bScore = 0, aLen = a.length, bLen = b.length;
		a = a.toLowerCase(), b = b.toUpperCase();
		for(var i=0;i<aLen || i<bLen;i++)
		{
			aScore += i < aLen ? a.charCodeAt(i) - 64 : 0;
			bScore += i < bLen ? b.charCodeAt(i) - 64 : 0;
		}
		return aScore/aLen - bScore/bLen;
	});
	return words;
}
→ More replies (4)

1

u/drb226 May 14 '12
ghci> :m +Data.List Data.Ord Data.Char
ghci> let wordScore = sum . map ((subtract (ord 'a' - 1)) . ord . toLower)
ghci> wordScore "Hat"
29
ghci> wordScore "Shoe"
47
ghci> let mySort = sortBy (comparing wordScore)
ghci> mySort $ words "Hat Shoe"
["Hat", "Shoe"]
ghci> let wordScore' str = fromIntegral (wordScore str) / fromIntegral (length str)
ghci> let mySort' = sortBy (comparing wordScore')

1

u/[deleted] May 14 '12
public static int wordValue(String word) {
	int sum = 0;
	word = word.toLowerCase();
	for(int i = 0; i < word.length(); i++)
		sum += word.charAt(i) - 'a' + 1;
	return sum;
}

public static void QuickSortWords(int[] values, String[] words, int low, int high) {
	int i = low, j = high;
	int mid = values[(low + high) / 2];
	
	while(i <= j) {
		while(values[i] < mid) i++;
		while(values[j] > mid) j--;
		if(i < j) {
			int temp = values[i];
			String word = words[i];
			values[i] = values[j];
			words[i] = words[j];
			values[j] = temp;
			words[j] = word;
			i++; j--;
		}
	}
	if(low < i - 1) QuickSortWords(values, words, low, i - 1);
	if(i < high) QuickSortWords(values, words, i, high);
}

public static String[] wordSort(String[] words) {
	int[] values = new int[words.length];
	for(int i = 0; i < words.length; i++)
		values[i] = wordValue(words[i]);
	QuickSortWords(values, words, 0, words.length - 1);
	return words;
}

2

u/lesleh May 15 '12

Why not just use Arrays.sort()?

2

u/DisasterTourist May 15 '12

Brilliant idea. Makes it a lot easier.

Here's the simple answer to the question in Java.

public static void main(String args[]) {
	    Challenge_51_Easy driver = new Challenge_51_Easy();
	    String a = "za";
	    String b = "aaa";
	    String names[] = {a, b};
	    Arrays.sort(names);
    }

0

u/lesleh May 16 '12

What exactly is wrong with using the functionality provided to you by your programming language of choice?

1

u/ret0 May 14 '12

C:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>


int mytotal(const char *str){
	int total=0;
	for(;*str;str++)
		total+=(*str)-(islower(*str)?96:64);
	return total;
}


int mycmp(const void *a, const void *b){
	return mytotal(*(const char **)b)-mytotal(*(const char **)a);
}


int main(int argc, char **argv){

	qsort((void *)(argv+1),argc-1,sizeof(char *),mycmp);

	for(int n=1;n<argc;n++){
		printf("%s\n",argv[n]);
	}

	return 0;
}

Compile with:

$ gcc -std=c99 -o mysort mysort.c

Run with:

$ ./mysort Hat Shoe

1

u/bh3 May 14 '12

Python:

def getSorted(l):
   m = [(sum(ord(c)-ord('a')+1 for c in s.lower())/float(len(s)),s) for s in l]
   return [s[1] for s in sorted(m, key=lambda s: s[0])]

1

u/StorkBaby May 14 '12 edited May 14 '12

Python, probably too much code here. edit: space before the code.

## generates the value of the word
## switch added for weighted extra credit
def word_val(word, weighted):
    val = 0
    for letter in string.lower(word):
        val += string.find(string.lowercase, letter)
    if weighted == True:
        val = val/len(word)
    return(val)

## creates a dictionary with the values
## will handle duplicate word values gracefully
def word_value(word_list, weighted=False):
    coll    = {}
    for w in word_list:
        temp_val = word_val(w, weighted)
        if not temp_val in coll:
            coll[temp_val] = []
        coll[temp_val].append(w)
    return(coll)
   
## prints the dictionary of values[words]
def word_order(word_dict):
    ordered = []
    key_list = word_dict.keys()
    key_list.sort()
    for k in key_list:
        for w in word_dict[k]:
            ordered.append(w)
    return(ordered)

## usage
test = ["test", "spaz", "booger", "foo", "bar"]
print(word_order(word_value(test)))
print(word_order(word_value(test, True)))

1

u/atheistscansuckit May 14 '12

One liner(each) in python. Wouldn't be hard to take the list from a file and keep it a one liner

print map(lambda z: z[1],sorted(map(lambda y: (lambda x: (sum([ord(l)-ord('a')+1 for l in x])/len(x))(y),y),'hat,shoe'.split(','))))
print map(lambda z: z[1],sorted(map(lambda y: (lambda x: sum([ord(l)-ord('a')+1 for l in x])(y),y),'hat,shoe'.split(','))))

1

u/emcoffey3 May 14 '12

Using C# and LINQ:

using System.Collections.Generic;
using System.Linq;

namespace RedditDailyProgrammer
{
    public static class Easy052
    {
        public static List<string> OrderBySum(List<string> list)
        {
            return list.OrderBy(s => StringSum(s)).ToList();
        }
        public static int StringSum(string s)
        {
            return s.ToUpper().ToCharArray().Select(c =>
            {
                return (int)(c - 64);
            }).Sum();
        }
        public static List<string> OrderBySumExtraPoints(List<string> list)
        {
            return list.OrderBy(s => StringSumExtraPoints(s)).ToList();
        }
        public static double StringSumExtraPoints(string s)
        {
            return s.ToUpper().ToCharArray().Select(c =>
            {
                return (int)(c - 64);
            }).Sum() / s.Length;
        }
    }
}

1

u/[deleted] May 14 '12

C. Solves the bonus question if BONUS_QUESTION is defined when compiling, using a preprocessor trick.

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#define BONUS_QUESTION

int char_score(char c) {
  if (isalpha(c))
    return (tolower(c) - 'a' + 1);
  return 0;
}

float word_score(char *s) {
  int i; float n = 0.0;
  for (i = 0; s[i]; i++)
    n += char_score(s[i]);
#ifdef BONUS_QUESTION
  n /= (float) i;
#endif
  return n;
}

int word_score_cmp(const void *a, const void *b) {
  float f = word_score(*(char**)a) - word_score(*(char**)b);
  return (f < 0.0) ? -1 : (f > 0.0);
}

int main(int argc, char *argv[]) {
  int i;

  argv++; /* skip program name */
  qsort(argv, argc - 1, sizeof(char*), word_score_cmp);

  for (i = 0; argv[i]; i++)
    printf("%10s = %3.2f\n", argv[i], word_score(argv[i]));

  return 0;
}

1

u/Rapptz May 15 '12 edited May 15 '12
#include <iostream>
#include <string>
#include <algorithm>
char alphabet[26] = { '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' };
int sumof(std::string s) {
int sum1 = 0;
transform(s.begin(), s.end(), s.begin(), ::tolower);
for(int i = 0; i<s.length(); i++) {
	for(int j=1; j<27; j++) {
		if (s[i] == alphabet[j-1])
			sum1+=j;
	}
}
return sum1;
}
int main() {
using namespace std;
string a, b;
cout << "Input a string: ";
getline(cin,a);
int a1 = sumof(a);
cout << "Input another string: ";
getline(cin,b);
int b1 = sumof(b);
if(b1 > a1)
	cout << "The largest string sum is " << b << " with a sum of " << b1 << " then " << a << " with a sum of " << a1 << endl;
else
	cout << "The largest string sum is " << a << " with a sum of " << a1 << " then " << b << " with a sum of " << b1 << endl;
}

1

u/totallygeek May 15 '12 edited May 15 '12

Edit Put in the code for extra points

Bash:

#!/bin/sh

function calcWordValue() {
  wordTotal=0
  divTotal=0
  str=`echo $1 | tr '[A-Z]' '[a-z]'`
  strLen=${#str}
  strSteps=$((strLen-1))
  for x in `seq 0 ${strSteps}` ; do
    oneChar=${str:x:1}
    oneCharVal=$( printf "%d" "'${oneChar}" )
    oneCharVal=$((oneCharVal-96))
    wordTotal=$((wordTotal+oneCharVal))
  done
  divTotal=$((wordTotal/strLen))
  echo "${str} ${strLen} ${wordTotal}" >> $redditFile1
  echo "${str} ${strLen} ${divTotal}" >> $redditFile2
}

redditFile1="/tmp/20120514e-1.txt"
redditFile2="/tmp/20120514e-2.txt"
rm -f $redditFile1 $redditFile2

for word in $@ ; do
  calcWordValue ${word}
done

echo "    Sorted by Character Value Summation"
for workLine in `sort -k3 -u < $redditFile1 | tr ' ' ':'`; do
  str=`echo $workLine | cut -d ':' -f 1`
  strLen=`echo $workLine | cut -d ':' -f 2`
  wordTotal=`echo $workLine | cut -d ':' -f 3`
  echo "    ${str}: Length=${strLen} Value=${wordTotal}"
done

echo ; echo "    Sorted by Word Value Divided by Length"
for workLine in `sort -k3 -u < $redditFile2 | tr ' ' ':'`; do
  str=`echo $workLine | cut -d ':' -f 1`
  strLen=`echo $workLine | cut -d ':' -f 2`
  divTotal=`echo $workLine | cut -d ':' -f 3`
  echo "    ${str}: Length=${strLen} Value=${divTotal}"
done

Output(s):

[sjain@bandarji dailyprogrammer]$ ./20120514e.sh Shoe Hat
Sorted by Character Value Summation
hat: Length=3 Value=29
shoe: Length=4 Value=47

Sorted by Word Value Divided by Length
shoe: Length=4 Value=11
hat: Length=3 Value=9