2

Given an array of chars, I am looking for the best way to find the first distinct char and its index in the array. This code seems to do the job, but I am wondering if there is a better way to do it without so many loops. Thanks for your input!

static string firstDistinctChar(char[] myChars)
    {
        string result = "No Distinct Chars found!";

        Dictionary<char, int> charDict = new Dictionary<char, int>();
        for (int i = 0; i < myChars.Length; i++)
        {//create dictionary of char and counts of char in array
            if (charDict.TryGetValue(myChars[i], out int count))
            {
                charDict[myChars[i]] = count + 1;
            }
            else
            {
                charDict.Add(myChars[i], 1);
            }
        }
        foreach (var item in charDict)
        {
            //remove all non distinct chars from dictionary
            if (item.Value > 1) { charDict.Remove(item.Key); }
        }
        for (int i = 0; i < myChars.Length; i++)
        {
            //loop thru each char in array and return first matching char and index
            if (charDict.TryGetValue(myChars[i], out _))
            {
                result = string.Format("The char: {0} is the first distinct char in the array with an index of : {1}", myChars[i], i);
                return result;
            }
        }
        return result;
    }
Super Jade
  • 5,609
  • 7
  • 39
  • 61
Kenny
  • 27
  • 4

2 Answers2

0

Well it could be shorted a lot using linq.

void Main()
{
    var z = firstDistinctChar("AABBCCddefg".ToCharArray());
    Console.WriteLine(z);

}
static string firstDistinctChar(char[] myChars)
{
    // Group chars in the array then take groups with count = 1 and extract only the first group 
    var group = myChars.GroupBy(c => c).Where(c => c.Count() == 1).FirstOrDefault();
    if (group != null)
    {
       // From the first group extract the first (and only) value
       char u = group.First();

       // Now find the position of the distinct char 
       // creating a new array until we reach the distinct character 
       int i = myChars.TakeWhile(c => c != u).Count();

       return string.Format("The char: {0} is the first distinct char in the array at index {1}", u,i);
    }
    else
       return "No Distinct Chars found!";
}

This works because according to this answer

GroupBy - The IGrouping objects are yielded in an order based on the order of the elements in source that produced the first key of each IGrouping. Elements in a grouping are yielded in the order they appear in source.

Is this better than your current solution? I am sure that is shorter but in terms of perfomance it should be tested with your actual data and without the proper comments is a little obscure

Steve
  • 213,761
  • 22
  • 232
  • 286
  • 1
    Thank you! Yours ran faster! It is a bit obscure without the comments. Thanks for the IGrouping info. – Kenny Nov 25 '19 at 02:54
0

I am wondering if there is a better way to do it without so many loops.


The biggest changes I would make are

  1. Remove the 2nd loop.
  2. Use the last loop to check for a char count of 1, which is what allows the removal of the 2nd loop.

The other comments are just my 2 cents.

static string FirstDistinctChar(char[] myChars)
{
    // You'll want to decide what to do if your parameter is null.
            
    Dictionary<char, int> charDict = new Dictionary<char, int>();

    // You're iterating thru every element, you don't need the index value, 
    // and you're not changing the collection, so use foreach instead of for.
    // foreach is preferred for readability and maintainability.
    foreach (char c in myChars)
    {
        if (charDict.TryGetValue(c, out int count))
        {
            charDict[c] = count + 1;
        }
        else
        {
            charDict.Add(c, 1);
        }
    }
            
    // It's not necessary to remove non-distinct chars from charDict;
    // just check for a value of 1. This allows the removal of a loop from your code. :-)
    for (int i = 0; i < myChars.Length; ++i)
    {
        if (charDict[myChars[i]] == 1)
        {
            // Placeholders are difficult to read. I use string interpolation (c# 6 and up).
            return $"The char {myChars[i]} is the first distinct char in the array with an index of {i}";
        }
    }

    return "No distinct chars found.";
}
Super Jade
  • 5,609
  • 7
  • 39
  • 61