I applied for a job as a C#/.NET Junior Developer, and had a test to do::
Using names.txt (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.
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 × 53 = 49714. What is the total of all the name scores in the file?
I'm looking for some constructive comments on how I could have done it better.
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace Name.Data.RetrieveNames
{
public class Names
{
public string Name { get; set; }
}
public static class RetrieveListOfNames
{
public static IEnumerable<Names> LstOfNames()
{
//**********************************
//
//File location is stored in app.config file,
//this allows for ease in case the file needs
//to be moved somewhere else.
//So 1st check that it exists
//
//**********************************
var fileExists = File.Exists(ConfigurationManager.AppSettings["LocationOfNamesFile"]);
//**********************************
//
//If file does not exist, throw file not found exception, as no point in continuing
//
//**********************************
if (!fileExists) throw new FileNotFoundException("FileNotFound Check AppSettings Location");
//**********************************
//Set buffer size, on huge file this can help with performance
//
//**********************************
const int bufferSize = 1024;
//**********************************
//
//Here we create the list and open the file and read all the names
//
//**********************************
var data = new List<Names>();
using (var fileStream = File.OpenRead(ConfigurationManager.AppSettings["LocationOfNamesFile"]))
using (var streamReader = new StreamReader(fileStream, Encoding.UTF8, true, bufferSize))
{
string line;
while ((line = streamReader.ReadLine()) != null)
{
//Split the string on the comma
string[] namesArray = Regex.Split(line, ",");
//Sort the names a-z
Array.Sort(namesArray);
//Loop over all names and add to list
data.AddRange(namesArray.Select(names => new Names
{
Name = names.ToLower()
}));
}
}
//Finally return the names
return data;
}
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text.RegularExpressions;
using Name.Data.RetrieveNames;
namespace Name.UI
{
class Program
{
//********************************************************************
//Names scores
//Problem 22
//Using names.txt (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.
//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 × 53 = 49714.
//What is the total of all the name scores in the file?
//
//********************************************************************
static void Main(string[] args)
{
try
{
//********************************************************************
//List of names returned from text file
//********************************************************************
var data = RetrieveListOfNames.LstOfNames().ToList();
//********************************************************************
//My own interest to see how long it takes to run code
Stopwatch timer = new Stopwatch();
//********************************************************************
//Create list to hold the values
//********************************************************************
List<string> sumOffAllNames = new List<string>();
timer.Start();
//********************************************************************
//Loop over names replacing a-z with numbers 1-26, make all letters lowercase
//********************************************************************
List<string> listOfNames = data.Select(v => Regex.Replace(v.Name.Trim('"').ToLower(), "a", "1,")
.Replace("b", "2,")
.Replace("c", "3,")
.Replace("d", "4,")
.Replace("e", "5,")
.Replace("f", "6,")
.Replace("g", "7,")
.Replace("h", "8,")
.Replace("i", "9,")
.Replace("j", "10,")
.Replace("k", "11,")
.Replace("l", "12,")
.Replace("m", "13,")
.Replace("n", "14,")
.Replace("o", "15,")
.Replace("p", "16,")
.Replace("q", "17,")
.Replace("r", "18,")
.Replace("s", "19,")
.Replace("t", "20,")
.Replace("u", "21,")
.Replace("v", "22,")
.Replace("w", "23,")
.Replace("x", "24,")
.Replace("y", "25,")
.Replace("z", "26,") + 0).ToList();
//********************************************************************
//Variable for name row
int nameId = 1;
//********************************************************************
//Loop over all rows returned from above foreach loop and add up each value to get total for name
//Then times that by position in table
//As all names are in alphabetical order, the variable nameId will increment by 1 on every loop
//So I can use that to muliple total name value
//********************************************************************
foreach (var s in listOfNames)
{
var sumArray = string.Join("", s.ToArray());
var sumOfName = (sumArray.Split(',').Sum(x => int.Parse(x)) * nameId++).ToString();
sumOffAllNames.Add(sumOfName);
//Console.WriteLine(nameNumber);
}
//********************************************************************
//Turn list sumOffAllNames into string
//Then add all values up to get total
//********************************************************************
string characterArray = string.Join(",", sumOffAllNames.ToArray());
int number = characterArray.Split(',').Sum(x => int.Parse(x));
timer.Stop();
//********************************************************************
//OK done display total and number of names and time to run code
Console.WriteLine("Total is {0} from {1} names, time taken {2} seconds", number.ToString("##,000"), data.Count.ToString("##,000"), ((float)timer.ElapsedTicks)/Stopwatch.Frequency);
Console.Read();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.Read();
}
}
}
}