Thursday, July 10, 2025

Extension Methods in C#

I was explaining extension methods in C# to somebody and realized it was a good topic for a blog post, so here we are.

Extension methods are a way to enhance (or extend) an existing object. If you've done any significant coding with C# I can virtually guarantee you've already used extension methods that were built-in to the framework. Things like " banana ".Trim(), which removes leading and trailing whitespace from the string. But you can also create your own extension methods and it's actually pretty easy to do.

First you need to identify what you're trying to extend. For example, if you always want to safely convert a string to an integer and return -1 when the string is not an integer, would you be extending strings or ints? The answer is strings.
 
I actually wrote a separate post with some examples of string extensions that I use pretty frequently. Basically, we're extending (hence the name) the framework's built-in capabilities so we can manipulate an object (type) more easily. Extension methods are a great way to avoid littering your application with helper methods like "GetTrimmedString(string toTrim)". But you want to be aware of unnecessarily polluting your code base with extension methods that are only used in one place.

Fuzzy Matching in C#

I've been working on a project where we allow users to provide us a .csv file and tell us about it, like what kind of data is in which column. Think of it like this: we have a fixed list of data points that we need to have mapped and the user is going to give us a file that contains all the data, but we don't know which column will have which piece of information so the user has to tell us. If we need First Name, Last Name, and Age, the user just has to tell us which column in their file has which value. We want to make that as easy as possible so we check the header in their file to see if we can deduce that information so the user doesn't have to. It's easy if the columns are named First Name, Last Name, and Age, but it gets a little trickier when they're named FName, LName, and AgeInYears. That's where fuzzy matching comes in.

We decided to use a library called Fuzzy Sharp (there are several with that name so be cautious when choosing one) to do the heavy lifting for us. It's pretty simple to use, but there are lots of options and the "documentation" isn't super clear. Fortunately in 2025 we have AI to help us make sense of the nonsensical!

In our first attempt we checked for an exact match manually, then stripped off special characters from both sets for comparison and checked for another "exact" match, then finally relented and used the FuzzySharp library to check for a match:

 

private int FindSourceColumnNumber(string destinationNameIEnumerable<stringcolumnNames)
{
    var exactMatch = columnNames.Select((nameindex) => new { Name = name, Position = index })
        .FirstOrDefault(a => a.Name.Equals(destinationNameStringComparison.OrdinalIgnoreCase));
 
    if (exactMatch is not null)
    {
        return exactMatch.Position;
    }
 
    var strippedColumnNames = columnNames
        .Select((nameindex) => new {
            Name = name,
            Position = index,
            StrippedName = SpecialCharacterReplacementRegex().Replace(name"")
        });
    var strippedDestinationName = SpecialCharacterReplacementRegex().Replace(destinationName"");
 
    var strippedMatch = strippedColumnNames
        .FirstOrDefault(name => string.Equals(namestrippedDestinationNameStringComparison.InvariantCultureIgnoreCase));
 
    if (strippedMatch is not null)
    {
        return strippedMatch.Position;
    }
 
    var fuzzyMatch = strippedColumnNames
        .Select((nameindex) => new { Name = name, Position = index, Score = Fuzz.Ratio(strippedDestinationNamename) })
        .Where(x => x.Score >= 70)
        .OrderByDescendinx(x => x.Score)
        .FirstOrDefault();
 
    return fuzzyMatch is not null ? fuzzyMatch.Position : -1;
}
That was fine, but it turned out there was a much better way to do this by taking advantage of the FuzzySharp library. We were able to simplify our code to just this:
private intFindSourceColumnNumber(string destinationNameIEnumerable<stringcolumnNames)
{
    var exactMatch = columnNames.Select((nameindex) => new { Name = name, Position = index })
        .FirstOrDefault(a => a.Name.Equals(destinationNameStringComparison.OrdinalIgnoreCase));
 
    if (exactMatch is not null)
    {
        return exactMatch.Position;
    }
 
    // Step 2: Fuzzy match (slower, but more flexible)
    var fuzzyMatch = columnNames
        .Select((nameindex) => new { Name = name, Position = index, Score = Fuzz.Ratio(destinationNamenamePreprocessMode.Full) })
        .Where(x => x.Score >= 70)
        .OrderByDescending(x => x.Score)
        .FirstOrDefault();
 
    return fuzzyMatch is not null ? fuzzyMatch.Position : null;
}
Adding the PreprocessMode.Full parameter tells FuzzySharp to strip out non-alphanumeric characters on its own. Since the authors of that library focused on speed and efficiency we've basically decided to trust that they're doing a better job with it than we were when we were using the Regex match capability. There's a ton more that FuzzySharp can do, but this is the extent of what we needed so I didn't delve too deep into its other features.

Friday, March 28, 2025

Distinct Array Values in JavaScript

Sometimes when you're working with collections (in any language) you find yourself needing to get just the distinct list of items in the collection. JavaScript has an object called a Set that makes doing this with arrays really, really easy.

Start with an array of primitives:

let arr = [1, 2, 3, 4, 5, 5, 4, 3, 2, 1, 1, 1, 1, 3, 4, 5, 6]

From that array, create a Set: 

let set = new Set(arr)

Convert it back to an array (this step is optional because you may find working with the Set directly meets your needs):

let result = Array.from(set);

That's it. Now you have an array of distinct primitive values. If you have an array of complex objects, you can use this same trick, but it's a little... trickier.

let arr = [{id:1,name:'Frodo',relatives:[{id:2,name:'Bilbo'}]},{id:1,name:'Frodo',relatives:[{id:2,name:'Bilbo'}]}];
let set = new Set(arr.map(JSON.stringify));
let result = Array.from(set);

Tuesday, March 25, 2025

Setting Up esLint for an Angular 19 Project

The angular-eslint package makes setting up linting in an Angular project pretty easy, but due to some recent changes there are a few new steps I had to work out to get it working so I figured I'd put them here for next time.

  1. Install the angular-eslint package: ng add angular-eslint
  2. Rename the generated eslint.config.js to eslint.config.mjs
  3. Change the 3 require statements at the top of the config file to import statements
    1. const eslint = require("@eslint/js"); => import esLint from '@eslint/js';
    2. const tseslint = require("typescript-eslint"); => import tsEsLint from 'typescript-eslint';
    3. const angular = require("angular-eslint"); => import angular from 'angular-eslint';
  4. Change the module.exports to export default
    1. module.exports = tseslint.config( => export default tsEsLint.config(
  5. In package.json, add a "type" setting with a value of "module"

At this point, esLint should be all setup. It actually works before any of this, but I wanted to use a plugin (more on that in a moment) and that required me to make these changes.

So, about that plugin. esLint made the decision in 8.53 to stop including stylistic rules as part of the linting process. I understand the decision, but I don't like it. Fortunately, there's a plugin for stylistic linting that you can add and it's pretty easy now that the above changes have been implemented.

  1. Install @stylistic/eslint-plugin-ts package: npm install @stylistic/eslint-plugin-ts
  2. Import the plugin in eslint.config.mjs
    1. import stylisticPlugin from '@stylistic/eslint-plugin-ts'
  3. In eslint.config.mjs, add a node as a sibling to the "files" node for plugins:
    plugins: {
          stylistic: stylisticPlugin
        },
  4.  Add the individual style rules to the rules node of eslint.config.mjs
    1. For example, to enfore the 1 true brace style rule, add "stylistic/brace-style": ["error", "1tbs"],

That's it! esLint should be all good to go. If you install a live linter extension in your working environment (like the esLint plugin for VS Code) you should see all your lint rules - including stylistic ones - applied.

Friday, March 7, 2025

JavaScript Boolean Object

It has been a looooooong time since I posted. Not because I haven't had a ton to post about, but because at my core I'm super lazy. Anyway, here's a quick hitter on how to check if every property on an object is true using the Boolean function in JavaScript.

return Object.values(this.data.modal.validation).every(Boolean);

You do need to watch out for a couple of things if you want to use this. First, because of type coercion in JavaScript, an object that has pretty much any kind of data on a property will count as true. So if you had an object with a name property that had a value of "Mickey", that's true in this scenario. Second (and related), if you have a property with a value of 0 it will count as false, again due to type coercion.

I'm using this to check an object that only has boolean properties and it works very well.