获取第一个和最后一个字母之间的唯一字符数

Get count of unique characters between first and last letter

我正在尝试获取单词第一个字母和最后一个字母之间的唯一字符数。例如:如果我键入 Yellow,则预期输出为 Y3w,如果我键入 People,则输出应为 P4e,如果我键入 Money,则输出应为是 M3y。这是我试过的:

//var strArr = wordToConvert.Split(' ');
string[] strArr = new[] { "Money","Yellow", "People" };
List<string> newsentence = new List<string>();

foreach (string word in strArr)
{
    if (word.Length > 2)
    {
        //ignore 2-letter words
        string newword = null;

        int distinctCount = 0;
        int k = word.Length;
        int samecharcount = 0;
        int count = 0;

        for (int i = 1; i < k - 2; i++)
        {
            if (word.ElementAt(i) != word.ElementAt(i + 1))
            {
                count++;
            }
            else
            {
                samecharcount++;
            }
        }
        distinctCount = count + samecharcount;

        char frst = word[0];
        char last = word[word.Length - 1];
        newword = String.Concat(frst, distinctCount.ToString(), last);
        newsentence.Add(newword);
    }
    else
    {
        newsentence.Add(word);
    }
}

var result = String.Join(" ", newsentence.ToArray());

Console.WriteLine("Output: " + result);
Console.WriteLine("----------------------------------------------------");

使用此代码,我得到了 Yellow 的预期输出,但似乎不适用于 People 和 Money。我能做些什么来解决这个问题,或者我也想知道也许有更好的方法来做到这一点,例如使用 LINQ/Regex.

这是一个使用 Linq 的实现:

string[] strArr = new[]{"Money", "Yellow", "People"};
List<string> newsentence = new List<string>();
foreach (string word in strArr)
{
    if (word.Length > 2)
    {
        // we want the first letter, the last letter, and the distinct count of everything in between
        var first = word.First();
        var last = word.Last();
        var others = word.Skip(1).Take(word.Length - 2);

        // Case sensitive
        var distinct = others.Distinct();

        // Case insensitive
        // var distinct = others.Select(c => char.ToLowerInvariant(c)).Distinct();

        string newword = first + distinct.Count().ToString() + last;
        newsentence.Add(newword);
    }
    else
    {
        newsentence.Add(word);
    }
}

var result = String.Join(" ", newsentence.ToArray());
Console.WriteLine(result);

输出:

M3y Y3w P4e

请注意,这不考虑大小写,因此 FiIsSh 的输出是 4。

也许不是最高效的,但这是另一个使用 linq 的例子:

var words = new[] { "Money","Yellow", "People" };
var transformedWords = words.Select(Transform);
var sentence = String.Join(' ', transformedWords);

public string Transform(string input)
{
    if (input.Length < 3)
    {
        return input;
    }
    var count = input.Skip(1).SkipLast(1).Distinct().Count();
    return $"{input[0]}{count}{input[^1]}";
}

您可以借助 Linq 来实现它。例如(C# 8+)

private static string EncodeWord(string value) => value.Length <= 2
  ? value
  : $"{value[0]}{value.Substring(1, value.Length - 2).Distinct().Count()}{value[^1]}";

演示:

  string[] tests = new string[] {
    "Money","Yellow", "People"
  };

  var report = string.Join(Environment.NewLine, tests
    .Select(test => $"{test} :: {EncodeWord(test)}"));

  Console.Write(report);

结果:

Money :: M3y
Yellow :: Y3w
People :: P4e

我会为此目的使用 Linq:

            string[] words = new string[] { "Yellow" , "People", "Money", "Sh" }; // Sh for 2 letter words (or u can insert 0 and then remove the trinary operator)
            foreach (string word in words)
            {
                int uniqeCharsInBetween = word.Substring(1, word.Length - 2).ToCharArray().Distinct().Count();
                string result = word[0] + (uniqeCharsInBetween == 0 ? string.Empty : uniqeCharsInBetween.ToString()) + word[word.Length - 1];
                Console.WriteLine(result);
            }

很多人提出了一些很好的解决方案。我为您提供两种解决方案:一种使用 LINQ,另一种不使用。

LINQ,大概和其他的没什么区别

if (str.Length < 3) return str;

var midStr = str.Substring(1, str.Length - 2);
var midCount = midStr.Distinct().Count();
return string.Concat(str[0], midCount, str[str.Length - 1]);

非 LINQ

if (str.Length < 3) return str;
    
var uniqueLetters = new Dictionary<char, int>();
var midStr = str.Substring(1, str.Length - 2);
foreach (var c in midStr)
{
   if (!uniqueLetters.ContainsKey(c))
   {
      uniqueLetters.Add(c, 0);
   }
}
        
var midCount = uniqueLetters.Keys.Count();
return string.Concat(str[0], midCount, str[str.Length - 1]);

我用以下 6 个字符串对此进行了测试:

Yellow
Money
Purple
Me
You
Hiiiiiiiii

输出:

LINQ: Y3w, Non-LINQ: Y3w  
LINQ: M3y, Non-LINQ: M3y  
LINQ: P4e, Non-LINQ: P4e  
LINQ: Me, Non-LINQ: Me  
LINQ: Y1u, Non-LINQ: Y1u  
LINQ: H1i, Non-LINQ: H1i

Fiddle

在性能方面,我猜它们几乎相同,即使不完全相同,但我还没有 运行 对这两种方法进行任何真正的性能测试。我无法想象它们会有很大的不同,如果有的话。唯一真正的区别是第二条路线将 Distinct() 扩展到它可能在幕后所做的事情(我没有查看源代码以查看是否属实,但这是一种非常常见的计算方式.而且第一条路线肯定是代码少