views:

145

answers:

6

Here is how I would write a function to make an acronym in Java style:

    string makeAcronym(string str)
    {
        string result = "";
        for (int i = 0; i < str.Length; i++)
        {
            if (i == 0 && str[i].ToString() != " ")
            {
                result += str[i];
                continue;
            }

            if (str[i - 1].ToString() == " " && str[i].ToString() != " ")
            {
                result += str[i];
            }
        }

        return result;
    }

Is there a more elegant way I can do it with LINQ, or using some built in C# function?

A: 
string makeAcronym(string str)
{
    return new string(str.Split(new [] {' '}, 
        StringSplitOptions.RemoveEmptyEntries).Select(s => s[0]).ToArray());
}
Yuriy Faktorovich
@Reed fixed. Damn limits
Yuriy Faktorovich
+7  A: 

Here are a couple of options

A .NET 4 only option using string.Join:

 string acronym = string.Join(string.Empty,
      input.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries).Select(s => s[0])
      );

In .NET 3.5 (or 4.0), you can do:

 string acronym = new string(input.Split(new[] {' '}, 
      stringSplitOptions.RemoveEmptyEntries).Select(s => s[0]).ToArray());

Another option (my personal choice), based on your original logic:

 string acronym = new string(
      input.Where( (c,i) => c != ' ' && (i == 0 || input[i-1] == ' ') )
      .ToArray()
    );
Reed Copsey
@Reed, you'll need .ToArray() in there after your Select. (Unless .net4 no longer requires this conversion... I don't know)
spender
@spender: Not in .NET 4 (they finally added a join on IEnumerable) - only in 3.5... http://msdn.microsoft.com/en-us/library/dd783876.aspx
Reed Copsey
@Reed - looks like a stray comma in example 1, which still won't compile for me.
Steve Townsend
@Steve: Corrected now.
Reed Copsey
@Reed, np, you got the +1 anyhow :-)
Steve Townsend
+4  A: 

You can do this quite nicely using a Regex/Linq combo:

String
    .Join("",
        Regex
            .Matches("this is a test",@"(?<=^| )\w")
            .Cast<Match>()
            .Select(m=>m.Value)
            .ToArray()
    )
spender
do you really need regex? What about `Char.IsWhitespace`?
Rosarch
No, you probably don't need Regex, but it does give you better control over what represents whitespace between words. If the list grew to include punctuation (for instance), Regex would probably be the tersest means of solving this. Might be useful.
spender
+2  A: 

LINQ can work for this but generally I find it's better to build up string values using StringBuilder instance. This allows you to avoid unnecessary string allocations.

string makeAcronym(string str) { 
  var builder = new StringBuilder();
  for ( var i = 0; i < str.Length; i++ ) { 
    var c = str[i];
    if ( c == ' ' ) {
      continue;
    }
    if ( i == 0 || str[i-1] == ' ' ) {
      builder.Append(c);
    }
  }
  return builder.ToString();
}
JaredPar
@Reed, not necessarily. I even considered making the inner part of the loop a LINQ query to return the `char` to put into the builder (i just got lazy and did it the for route). The only performance aspect about this I meant to assert is that it doesn't allocate any intermediate strings.
JaredPar
@JaredPar: I realized that after I reread your comment, which was why I deleted my comment ;) I agree, though, that eliminating the intermediate strings is very important here.
Reed Copsey
+1  A: 

You can use the LINQ Aggregate method to do this in a fairly elegant way.

Something like this:

private static string MakeAcronym2(string str)
{
    return str.Split(' ').Aggregate("", (x, y) => x += y[0]);
}
mtreit
This fails if any of the substrings is empty. And aggregation using a StringBuilder would be faster.
CodeInChaos
I challenge the notion that StringBuilder would be perceptibly faster in practice.
mtreit
@CodeInChaos: Also, can you give an example of input that will cause this to fail? I'm not quite sure I agree with your empty substring statement. Thanks!
mtreit
I think any string containing consecutive spaces and the empty string should fail because y[0] doesn't work if the string is empty.
CodeInChaos
@CodeInChaos: I think you're mistaken. Try it out and see.
mtreit
I just tried in LinqPad and both throw an IndexOutOfRange Exception.
CodeInChaos
@CodeInChaos: Yes, you're right. My test program had a bug that was masking this.
mtreit
+1  A: 

Here's a technique I haven't seen so far. It depends on the assumption that all the letters that should be in the acronym (and only those letters) are in upper-case in the string.

string MakeAcronym(string input)
{
    var chars = input.Where(Char.IsUpper).ToArray();
    return new String(chars);
}

// MakeAcronym("Transmission Control Protocol") == "TCP"
Joel Mueller