Avatar of newTimesNow

newTimesNow's solution

to Anagram in the C# Track

Published at Sep 20 2019 · 0 comments
Instructions
Test suite
Solution

Note:

This exercise has changed since this solution was written.

Given a word and a list of possible anagrams, select the correct sublist.

Given "listen" and a list of candidates like "enlists" "google" "inlets" "banana" the program should return a list containing "inlets".

Running the tests

To run the tests, run the command dotnet test from within the exercise directory.

Initially, only the first test will be enabled. This is to encourage you to solve the exercise one step at a time. Once you get the first test passing, remove the Skip property from the next test and work on getting that test passing. Once none of the tests are skipped and they are all passing, you can submit your solution using exercism submit Anagram.cs

Further information

For more detailed information about the C# track, including how to get help if you're having trouble, please visit the exercism.io C# language page.

Source

Inspired by the Extreme Startup game https://github.com/rchatley/extreme_startup

Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

AnagramTest.cs

// This file was auto-generated based on version 1.4.0 of the canonical data.

using Xunit;

public class AnagramTest
{
    [Fact]
    public void No_matches()
    {
        var candidates = new[] { "hello", "world", "zombies", "pants" };
        var sut = new Anagram("diaper");
        Assert.Empty(sut.FindAnagrams(candidates));
    }

    [Fact(Skip = "Remove to run test")]
    public void Detects_two_anagrams()
    {
        var candidates = new[] { "stream", "pigeon", "maters" };
        var sut = new Anagram("master");
        var expected = new[] { "stream", "maters" };
        Assert.Equal(expected, sut.FindAnagrams(candidates));
    }

    [Fact(Skip = "Remove to run test")]
    public void Does_not_detect_anagram_subsets()
    {
        var candidates = new[] { "dog", "goody" };
        var sut = new Anagram("good");
        Assert.Empty(sut.FindAnagrams(candidates));
    }

    [Fact(Skip = "Remove to run test")]
    public void Detects_anagram()
    {
        var candidates = new[] { "enlists", "google", "inlets", "banana" };
        var sut = new Anagram("listen");
        var expected = new[] { "inlets" };
        Assert.Equal(expected, sut.FindAnagrams(candidates));
    }

    [Fact(Skip = "Remove to run test")]
    public void Detects_three_anagrams()
    {
        var candidates = new[] { "gallery", "ballerina", "regally", "clergy", "largely", "leading" };
        var sut = new Anagram("allergy");
        var expected = new[] { "gallery", "regally", "largely" };
        Assert.Equal(expected, sut.FindAnagrams(candidates));
    }

    [Fact(Skip = "Remove to run test")]
    public void Does_not_detect_non_anagrams_with_identical_checksum()
    {
        var candidates = new[] { "last" };
        var sut = new Anagram("mass");
        Assert.Empty(sut.FindAnagrams(candidates));
    }

    [Fact(Skip = "Remove to run test")]
    public void Detects_anagrams_case_insensitively()
    {
        var candidates = new[] { "cashregister", "Carthorse", "radishes" };
        var sut = new Anagram("Orchestra");
        var expected = new[] { "Carthorse" };
        Assert.Equal(expected, sut.FindAnagrams(candidates));
    }

    [Fact(Skip = "Remove to run test")]
    public void Detects_anagrams_using_case_insensitive_subject()
    {
        var candidates = new[] { "cashregister", "carthorse", "radishes" };
        var sut = new Anagram("Orchestra");
        var expected = new[] { "carthorse" };
        Assert.Equal(expected, sut.FindAnagrams(candidates));
    }

    [Fact(Skip = "Remove to run test")]
    public void Detects_anagrams_using_case_insensitive_possible_matches()
    {
        var candidates = new[] { "cashregister", "Carthorse", "radishes" };
        var sut = new Anagram("orchestra");
        var expected = new[] { "Carthorse" };
        Assert.Equal(expected, sut.FindAnagrams(candidates));
    }

    [Fact(Skip = "Remove to run test")]
    public void Does_not_detect_a_anagram_if_the_original_word_is_repeated()
    {
        var candidates = new[] { "go Go GO" };
        var sut = new Anagram("go");
        Assert.Empty(sut.FindAnagrams(candidates));
    }

    [Fact(Skip = "Remove to run test")]
    public void Anagrams_must_use_all_letters_exactly_once()
    {
        var candidates = new[] { "patter" };
        var sut = new Anagram("tapper");
        Assert.Empty(sut.FindAnagrams(candidates));
    }

    [Fact(Skip = "Remove to run test")]
    public void Words_are_not_anagrams_of_themselves_case_insensitive_()
    {
        var candidates = new[] { "BANANA", "Banana", "banana" };
        var sut = new Anagram("BANANA");
        Assert.Empty(sut.FindAnagrams(candidates));
    }
}
using System;

public class Anagram
{
    //object string property for use within class method FindAnagrams, manipulate case for ease of code
    private string originalWord;

    public Anagram(string baseWord)
    {
        originalWord = baseWord.ToLower();
        //tests are successful with exception commented out, is this an acceptable solution?
        //throw new NotImplementedException("You need to implement this function.");
    }

    //General Algorith: compare Anagram.baseword to potential matches one by one
        //If the words are not equal length it is not a valid anagram
        //If the words are identical they are duplicates and not a valid anagram
        //Otherwise count the number of occurances of each letter in the original word, compare to the 
        //count for that character in the potential test word.  If every character in the original words appears in the test word
        //the same number of times it is an anagram

    public string[] FindAnagrams(string[] potentialMatches)
    {
        //initialize
        int numPotential = potentialMatches.Length;
        int[] isValid = new int[numPotential];
        int numValid = 0;
        int resultBuildPointer = 0;
        int origCharCount, testCharCount,j;
        string testWord;
        bool noMismatchFound;
        string[] matches;


        //test potential anagrams one by one
        for (int i = 0; i < numPotential; i++)
        {
            origCharCount = 0;
            testCharCount = 0;
            j = 0;
            //weird implementation by assuming a true anagram and then trying to disprove; "innocent until proven guilty" 
            //easiest way I could think of running this at the moment, certain scenarios will not benefit from a false positive most likley
            //further protection should be added -NH

            noMismatchFound = true;
            testWord = potentialMatches[i].ToLower();

            //first if words are of different lenghts, mark as invalid and skip following loop, protects against 
            //potential words with all valid letter counts but with additional unique letters as well
            if (originalWord.Length != testWord.Length) noMismatchFound = false;

            //words cannot be anagrams of themselves either, protect against that special case
            if (originalWord.Equals(testWord)) noMismatchFound = false;


            //count the number of occurances of each character in the original word and
            //determine if the test word has the same count
             while (noMismatchFound && j < originalWord.Length)
            {
               
                    //count num of times each charater appears one by one (if duplicate letters will count multi times and compare multi times)
                    foreach (char searchLetterOrig in originalWord)
                    {
                        if (originalWord.Substring(j, 1).Equals(searchLetterOrig.ToString()))
                        {
                            origCharCount++;
                        }
                    }
                    //count number of times the original character appears in the test word
                    foreach (char searchLetterTest in testWord)
                    {
                        if (originalWord.Substring(j, 1).Equals(searchLetterTest.ToString()))
                        {
                            testCharCount++;
                        }
                    }
                    //compare character count to determine if a match.  If a match search the next letter if available,
                    //if not exit the loop and continue
                    if(origCharCount == testCharCount)
                    {
                    j++;
                    }
                    else
                    {
                    noMismatchFound = false;
                    }

            }

             //count number of valid anagrams for output array initialization and identify in array to flag anagrams for output
             if (noMismatchFound)
            {
                numValid++;
                isValid[i] = 1;
            }
            else
            {
                isValid[i] = 0;
            }
            
        }


        //build array of valid anagrams
        matches = new string[numValid];
        for(int k = 0; k < numPotential; k++)
        {
            if (isValid[k] == 1)
            {
                matches[resultBuildPointer] = potentialMatches[k];
                resultBuildPointer++;
            }
        }


        return matches;
        throw new NotImplementedException("You need to implement this function.");
    }
}

Community comments

Find this solution interesting? Ask the author a question to learn more.

What can you learn from this solution?

A huge amount can be learned from reading other people’s code. This is why we wanted to give exercism users the option of making their solutions public.

Here are some questions to help you reflect on this solution and learn the most from it.

  • What compromises have been made?
  • Are there new concepts here that you could read more about to improve your understanding?