Thursday, August 7, 2014

C# finding duplicates in a List using LINQ



Suppose you have a list that contains entries repeated more than once.
Using LINQ you can get the repeated elements and their values.

The easiest way to solve the problem is to group the elements based on their value, and then pick a rapresentative of the gorup if the elements in it are more than 1.
In linq, this translates to:
    var query = lst.GroupBy(x=>x)

              .Where(g=>g.Count()>1)

              .Select(y=>y.Key)

              .ToList();

You can replace x=>x with x => x.Property if your list is a list of complex objects and you want to search for a specific duplicate value. If you compare objects you need to override equals.
If you want to know how many times the elements are repeated, you can use:

    var query = lst.GroupBy(x=>x)

              .Where(g=>g.Count()>1)

              .Select(y=> new { Element = y.Key, Counter = g.Count()})

              .ToList();

Submit this story to DotNetKicks

Saturday, July 26, 2014

Slugify a tile in excel


So, this in not properly a C# article.
I needed to write a function in Excel that create a slug (or a premalink) out of a title.
Permalink is a valid url created out of a piece of text (usually a blog post title).
The operation are quite simple: all lowercase, replace spaces and non alphabet characters with -, convert accents to plain (eg à becames a).
So in excel just VBA works as standard, so I take the slugify funcion in Orchard CMS open source that is C# and I converted in VBA.
Pretty easy? No.
Anyway I did it...

The original code follows:

        private string Slugify(FillSlugContext slugContext) {
            _slugEventHandler.FillingSlugFromTitle(slugContext);

            if (!slugContext.Adjusted) {

                var disallowed = new Regex(@"[/:?#\[\]@!$&'()*+,.;=\s\""\<\>\\\|%]+");

                var cleanedSlug = disallowed.Replace(slugContext.Title, "-").Trim('-','.');

                slugContext.Slug = Regex.Replace(cleanedSlug, @"\-{2,}", "-");

                if (slugContext.Slug.Length > 1000)
                    slugContext.Slug = slugContext.Slug.Substring(0, 1000).Trim('-', '.');

                slugContext.Slug = StringExtensions.RemoveDiacritics(slugContext.Slug.ToLower());
            }
            
            _slugEventHandler.FilledSlugFromTitle(slugContext);

            return slugContext.Slug;
        }

And this is the VBA result...


Function CreateSlug(text As String) As String
    
    Dim cleanedSlug As String
    cleanedSlug = text
    
    'Regex that replaces any invalid char with an -
    Set regEx = New RegExp
    regEx.Pattern = "[:?#\[\]@!$&'()*+,.;=\s\""\<\>\\\|%]+"
    regEx.IgnoreCase = True

    'The loop is needed because in vba it matches just first char in string
    Dim tm As String
    Do
        tm = cleanedSlug
        cleanedSlug = regEx.Replace(cleanedSlug, "-")
    Loop While (tm <> cleanedSlug)
    
    'removes all trailing - left    
    cleanedSlug = Trim(cleanedSlug, "-")

    'if there are 2 - replace with 1    
    regEx.Pattern = "\-{2,}"
    cleanedSlug = regEx.Replace(cleanedSlug, "-")

    'all lowercase
    cleanedSlug = LCase(cleanedSlug)

    'remove accents
    cleanedSlug = ReplaceAccents(cleanedSlug)

    'but why Vba designers removed the return keyword?
    CreateSlug = cleanedSlug
    
    Set regEx = Nothing
End Function
This helper function mimics the trim specific characters on the end of a string that does not exists in vba
Function Trim(text As String, trailing As String)

    If (Right(text, Len(trailing)) = trailing) Then
        Trim = Left(text, Len(text) - Len(trailing))
    Else
        Trim = text
    End If

End Function
This helper function remove specific accents in a string replacing with normal cheracters
Function ReplaceAccents(text As String)
    Const AccChars As String = "àáâãäåçèéêëìíîïðñòóôõöùúûüýÿø"
    Const RegChars As String = "aaaaaaceeeeiiiidnooooouuuuyyo"

    For J = 1 To Len(AccChars)
        text = Replace(text, Mid(AccChars, J, 1), Mid(RegChars, J, 1), compare:=vbBinaryCompare)
    Next J

    ReplaceAccents = text
End Function

Submit this story to DotNetKicks

Friday, February 14, 2014

The specified solution configuration “Debug|BNB” is invalid

Problem

When you try to build from command prompt or batch file you get the error

‘The specified solution configuration “Debug|BNB” is invalid. Please specify a valid solution configuration using the Configuration and Platform properties (e.g. MSBuild.exe Solution.sln /p:Configuration=Debug /p:Platform=”Any CPU”) or leave those properties blank to use the default solution configuration.

Background

You have an HP computer.
A system wide setting of an environment variable called "Platform" seems to override any other setting.

The issue

At build-time the compiler has to know what the target platform of your code, i.e. the system architecture like X86, 64bit etc. To do so it searches to "Platform" variable first, that is wrong in our case since BNB is not a valid platform for msbuild.

The solution

Delete the conflicting environment variable "Platform" in "Control Panel -- System -- Advanced -- Environment Variables". Restart your computer and try again.

Submit this story to DotNetKicks

Thursday, January 30, 2014

Encapsulate a string to act as an array of strings


Here is a quick snippet for expose in a class a string that contains values comma-separated (eg: value1,value2,value3) as an array.

    string myString;

    public string[] MyArray
    {
      get
      {
        if (string.IsNullOrEmpty(myString))
          return new string[0];
        return myString.Split(',');
      }

      set
      {
        myString = String.Join(",", value);
      }
    }

Sample input

 myString = "value1,value2,value3";

Result

myArray = string[]{ "value1", "value2", "value3" };

Tips

Be sure that string does not contains extra ',' in order to avoid unwanted splitting.

Submit this story to DotNetKicks

Asp Net config, automatically disable debug on production servers using a nice feature on machine.config

Developing in hurry is not the best thing to do but we all have to.
One of the things that I usually forgot to change in production is turning off the debug mode on web.config
So i forget to change:
<compilation debug ="true">
to
<compilation debug ="false">

So why leaving debug to true is so bad?
  • Compilation takes longer as batch optimizations are disabled 
  • Scripts and images from WebResources.axd will not be cached on the client 
  • Larger memory footprint 
  • Code will execute slower because of enabled debug paths
And you have to multiply for each site you are deplyoing in the same server.
This means wasting more memory, and having sites running much slower.
And you often cannot check every single web.config to see if the settings are right.

When deploying ASP.NET applications to a production environment, to force debug = false in all ASP.NET applications on the server, you can change the retail switch in machine.config:

<configuration>
    <system.web>
        <deployment retail="true" />
    </system.web>
</configuration>

This will also disable page output trace and force custom error pages.
This can be great generally, but can turn in a nightmare if you have a site that does not run properly since you have custom errors always on.
Solutions can be:
  • look at event log of server
  • install an aspnet logger like elmah
  • try debug locally
  • set retail to false for a while (not recommended because causes rebuild of all sites)
Have a nice day folks!

Submit this story to DotNetKicks

Monday, January 27, 2014

Using a Dictionary as the DataSource for a DropDownList

It is possible to use a Dictionary or even Dictionary<string> as the DataSource for a DropDownList directly, without having to iterate through the the Dictionary's KeyValuePair collection and populate the DropDownList's Items collection manually.

The text member is "value" and the value member is "key" when using one of these types of objects to bind to a DropdownList.

Dictionary<byte> dicTable = new Dictionary<byte>();
dicTable.Add(1, "One");
dicTable.Add(2, "Two");
dicTable.Add(3, "Three");
dicTable.Add(4, "Four");
cmbDropDownList.DataSource = dicTable;
cmbDropDownList.DataTextField = "Value";
cmbDropDownList.DataValueField = "Key";
cmbDropDownList.DataBind();

Submit this story to DotNetKicks