views:

79

answers:

3

Given an input string (such as D4C3B2A1) I want to sort the alphabet characters, and the numbers (ascending) then alternate them. Expected output would be: A1B2C3D4

The way I thought about doing this was using RegEx to pull out two strings, letters only, then numbers only.

Sorting both strings, then using substring to pull out each letter one by one and assigning it a new string. However, this seems like it would only work given you know orignal strings value/length etc.

Plus I figured there was a better way to do this to begin with.

Assume this needs to work for inputted string, not just the provided example string.

+2  A: 

To get (sorted) strings of letters and numbers you don't need regex, use Linq:

string s = "D4C3B2A1";

string letters = new String(s.Where(Char.IsLetter).OrderBy(c=>c).ToArray());
string numbers = new String(s.Where(Char.IsNumber).OrderBy(c=>c).ToArray());

To mix the two, you could use this:

public static string Mix(string s1, string s2)
{
    if (String.IsNullOrEmpty(s1))
        return s2;

    if (String.IsNullOrEmpty(s2))
        return s1;

    string s = String.Empty;

    for (int i=0; i<Math.Min(s1.Length, s2.Length); i++)
    {
        s += s1[i].ToString() + s2[i].ToString();
    }

    if (s1.Length > s2.Length)
        s += s1.Substring(s2.Length);
    else if (s2.Length > s1.Length)
        s += s2.Substring(s1.Length);

    return s;
}
Hans Kesting
+2  A: 

(Untested)

public static string Transform(string text)
{
  // Insert null-check here. You may also want to trim the string.

  var letters = text.Where(char.IsLetter).OrderBy(l => l).ToArray();
  var numbers = text.Where(char.IsNumber).OrderBy(n => n).ToArray();

  if (letters.Length != numbers.Length || (letters.Length + numbers.Length != text.Length))
       throw new FormatException("Text must consist only of an equal number of letters and numbers.");

  var zipped = letters.Zip(numbers, (l, n) => string.Concat(l, n));
  return string.Concat(zipped.ToArray());
}

If you are on .NET 3.5, you can replace the zipping line with:

var zipped = Enumerable.Range(0, text.Length).Select(i => string.Concat(letters[i], numbers[i]));
Ani
A: 

Supposing to have same numbers of digits and letters (i've tested it):

string s = "D4C1B2A3";

var s1 = s.Where(c => char.IsLetter(c)).OrderBy(c => c).ToArray();
var s2 = s.Where(c => char.IsDigit(c)).OrderBy(c => c).ToArray();

var sortedString = new string(s.Select((x, idx) => idx % 2 == 0 ? s1[idx / 2] : s2[(idx - 1) / 2]).ToArray());

To avoid "improper" use of s.Select you can change the last line with:

var sortedString = new string(Enumerable.Range(0, s.Length).Select(idx => idx % 2 == 0 ? s1[idx / 2] : s2[(idx - 1) / 2]).ToArray());
digEmAll