Craig Murphy dropped a little coding challenge on his blog the other day. This prompted me to write the responses as below. I’ve tried to target each one towards using a particular technology as the framework has developed.
Have a look and tell me which is your preferred answer, or propose a new one (but again try to target a language feature). I’d love to know who you why you choose that language feature over another.
Option 1. With Linq
private const string alphabet = "abcdefghijklmnopqrstuvwxyz";
static void Main(string[] args)
{
char c = Console.ReadKey().KeyChar;
var myChars = from character in alphabet
where character <= c
select character;
var fullRow = myChars.Skip(1).Reverse().Concat(myChars);
var myRows = (from character in myChars
select ConvertToSpaces(character, fullRow));
var reverseRows = myRows.Reverse().Skip(1);
myRows = myRows.Concat(reverseRows);
Console.WriteLine(Environment.NewLine);//Skip the ReadKey line
foreach (string line in myRows)
Console.WriteLine(line);
Console.ReadKey();
}
private static string ConvertToSpaces(char wanted, IEnumerable<char> characters)
{
return new string(
(from character in characters
select character == wanted ? character : ' ').ToArray());
}
Option 2. With Generics
class Program
{
private const string alphabet = "abcdefghijklmnopqrstuvwxyz";
static void Main(string[] args)
{
char c = Console.ReadKey().KeyChar;
List<char> myChars = new List<char>();
foreach (char character in alphabet)
{
if (character <= c)
myChars.Add(character);
}
List<char> temp = new List<char>(Reverse<char>(AllButFirst<char>(myChars)));
temp.AddRange(myChars);
string fullRow = new string(temp.ToArray());
List<string> myRows = new List<string>();
foreach (char character in myChars)
{
myRows.Add(ConvertToSpaces(character, fullRow));
}
IEnumerable<string> reverseRows = AllButFirst<string>(Reverse<string>(myRows));
myRows.AddRange(reverseRows);
Console.WriteLine(Environment.NewLine);//Skip the ReadKey line
foreach (string line in myRows)
Console.WriteLine(line);
Console.ReadKey();
}
private static IEnumerable<T> Reverse<T>(IEnumerable<T> myChars)
{
Stack<T> reverse = new Stack<T>();
foreach (T character in myChars)
{
reverse.Push(character);
}
while (reverse.Count > 0)
{
yield return reverse.Pop();
}
}
private static IEnumerable<T> AllButFirst<T>(IEnumerable<T> myChars)
{
bool first = true;
foreach (T character in myChars)
{
if (first)
first = false;
else
yield return character;
}
}
private static string ConvertToSpaces(char wanted, IEnumerable<char> characters)
{
StringBuilder result = new StringBuilder();
foreach (char character in characters)
{
result.Append(character == wanted ? character : ' ');
}
return result.ToString();
}
}
Option 3. Using IEnumerable
class ProgramDNv2
{
private const string alphabet = "abcdefghijklmnopqrstuvwxyz";
static void Main(string[] args)
{
DiamondChars diamond = new DiamondChars();
diamond.chars = GetChars( Console.ReadKey().KeyChar);
foreach (string line in diamond)
{
Console.WriteLine(line);
}
Console.ReadKey();
}
private static string GetChars(char MidChar)
{
string chars = alphabet.Substring(0, alphabet.IndexOf(MidChar) + 1);
return chars;
}
private class DiamondChars : IEnumerable<String>
{
public string chars;
#region IEnumerable<string> Members
public IEnumerator<string> GetEnumerator()
{
int index = 0;
foreach (char character in chars)
{
yield return MakeLine(character, index);
index++;
}
index--;
foreach (char character in chars.Reverse())
{
if (index < chars.Length - 1)
{
yield return MakeLine(character, index);
}
index--;
}
}
#endregion
private string MakeLine(char character, int index)
{
string line = new string(chars[index], 1).PadLeft(chars.Length - index);
if (index > 0)
return line + new string(chars[index], 1).PadLeft(index * 2);
else
return line;
}
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
}
Option 4. Simple recursion
class ProgramDNv1
{
static void Main(string[] args)
{
string input = "abcde";
StringBuilder result = new StringBuilder();
BuildDiamond(0, input, result);
Console.WriteLine(result);
}
private static void BuildDiamond(int index, string input, StringBuilder result)
{
string line = new string(input[index], 1).PadLeft(input.Length - index);
string line2 = new string(input[index], 1).PadLeft(index * 2);
result.Append(line);
if (index > 0)
result.Append(line2);
result.Append(Environment.NewLine);
if (index < input.Length - 1)
{
BuildDiamond(index + 1, input, result);
result.Append(line);
if (index > 0)
result.Append(line2);
result.Append(Environment.NewLine);
}
}
}
Now add a quick comment below telling you preferred implementation and briefly why. Thanks.