Avatar billede Mikker Praktikant
19. februar 2014 - 14:50 Der er 12 kommentarer og
1 løsning

PHP's ksort i C#

Hej Eksperter

Jeg skal sortere et dictionary<string,string> på præcis samme måde som PHP's ksort() funktion. Dvs.: 1.Uppercase, 2.Lowercase, 3. Tal.

Jeg har prøvet med IComparer.Ordinal men den returnerer tal før bogstaver.

Pft.
Avatar billede arne_v Ekspert
19. februar 2014 - 15:06 #1
Du skal nok lave din egen sammenlignings funktion.
Avatar billede Mikker Praktikant
19. februar 2014 - 15:11 #2
Har du noget bud på sådan en?
Avatar billede arne_v Ekspert
19. februar 2014 - 15:23 #3
Altsaa en klasse som implementerer IComparer<K>
Avatar billede arne_v Ekspert
19. februar 2014 - 15:23 #4
Jeg kan bixe et eksempel senere.

Men ellers google:

dictionary icomparer
Avatar billede Mikker Praktikant
19. februar 2014 - 15:29 #5
Hvis du kan diske op med et eksempel vil det være cool :)
Avatar billede Mikker Praktikant
19. februar 2014 - 15:34 #6
Når jeg kører nedenstående kode bliver sortedDict rigtigt nok sorteret, men "3" kommer som første element.

var sortedDict = new SortedDictionary<string, string>(StringComparer.Ordinal);
sortedDict.Add("b", "3");
sortedDict.Add("a", "2");
sortedDict.Add("3", "4");
sortedDict.Add("C", "1");

Så jeg skal altså have skiftet StringComparer.Ordinal ud med en funktion der smider tallene ind til sidst.
Avatar billede Mikker Praktikant
19. februar 2014 - 15:56 #7
Jeg har fundet frem til flg. løsning som ikke er særlig køn, men som virker:

class Program
    {
        static void Main(string[] args)
        {
            var queryCollection = new SortedDictionary<string, string>(new PhpKSort());
            queryCollection.Add("1", "7");
            queryCollection.Add("b", "4");
            queryCollection.Add("a", "3");
            queryCollection.Add("d", "5");
            queryCollection.Add("A", "1");
            queryCollection.Add("3", "9");
            queryCollection.Add("Q", "2");
            queryCollection.Add("e", "6");
        }
    }

    public class PhpKSort : IComparer<string>
    {
        public int Compare(string x, string y)
        {
            if (x == y)
                return 0;
            else if (IsNumeric<string>(x) && IsNumeric<string>(y)) // tal til tal
            {
                return string.Compare(x, y, StringComparison.Ordinal);
            }
            else if (IsNumeric<string>(x)) // tal til bogstav
            {
                return 1;
            }
            else if (IsNumeric<string>(y)) // bogstav til tal
            {
                return -1;
            }
            else // bogstav til bogstav
                return string.Compare(x, y, StringComparison.Ordinal);
        }

        private static bool IsNumeric<T>(T input)
        {
            double d;
            return double.TryParse(input.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out d);
        }
    }
Avatar billede Mikker Praktikant
19. februar 2014 - 16:13 #8
Eller det vil sige at den virker så længe key kun er et tal. Så det må være en ommer :)
Avatar billede arne_v Ekspert
20. februar 2014 - 03:03 #9
Det er lang tid siden jeg sidst har kodet saadan noget.

Men her et et bud:


using System;
using System.Collections.Generic;

namespace E
{
    public class PhpKSort : IComparer<string>
    {
        private const int OFFSET = 1000000;
        private int Value(char c)
        {
            if('0' <= c && c <= '9')
            {
                return 3 * OFFSET + c;
            }
            else if('A' <= c && c <= 'Z')
            {
                return 1 * OFFSET + c;   
            }
            else if('a' <= c && c <= 'z')
            {
                return 2 * OFFSET + c;   
            }
            else
            {
                throw new ArgumentException(c + " does not have an associated value");
            }
        }
        public int Compare(string x, string y)
        {
            int ix = 0;
            while(ix < x.Length || ix < y.Length)
            {
                if(ix >= x.Length) return -1;
                if(ix >= y.Length) return 1;
                int xval = Value(x[ix]);
                int yval = Value(y[ix]);
                if(xval < yval)
                {
                    return -1;
                }
                else if(xval > yval)
                {
                    return 1;
                }
                else
                {
                    ix++;
                }
            }
            return 0;
        }
    }
    public class Program
    {
        public static void Main(string[] args)
        {
            SortedDictionary<string, string> sdict = new SortedDictionary<string, string>(new PhpKSort());
            sdict.Add("1", "7");
            sdict.Add("b", "4");
            sdict.Add("a", "3");
            sdict.Add("d", "5");
            sdict.Add("A", "1");
            sdict.Add("3", "9");
            sdict.Add("Q", "2");
            sdict.Add("e", "6");
            sdict.Add("11", "7");
            sdict.Add("1b", "4");
            sdict.Add("1a", "3");
            sdict.Add("1d", "5");
            sdict.Add("1A", "1");
            sdict.Add("13", "9");
            sdict.Add("1Q", "2");
            sdict.Add("1e", "6");
            sdict.Add("b1", "7");
            sdict.Add("bb", "4");
            sdict.Add("ba", "3");
            sdict.Add("bd", "5");
            sdict.Add("bA", "1");
            sdict.Add("b3", "9");
            sdict.Add("bQ", "2");
            sdict.Add("be", "6");
            sdict.Add("A1", "7");
            sdict.Add("Ab", "4");
            sdict.Add("Aa", "3");
            sdict.Add("Ad", "5");
            sdict.Add("AA", "1");
            sdict.Add("A3", "9");
            sdict.Add("AQ", "2");
            sdict.Add("Ae", "6");
            foreach(KeyValuePair<string, string> entry in sdict)
            {
                Console.WriteLine("{0} -> {1}", entry.Key, entry.Value);
            }
            Console.ReadKey();
        }
    }
}
Avatar billede Mikker Praktikant
20. februar 2014 - 23:24 #10
Tak for det arne_v. Jeg kan ikke lige umiddelbart gennemskue hvad der sker, men jeg vil prøve at lege lidt med det.

/Michael
Avatar billede arne_v Ekspert
21. februar 2014 - 15:53 #11
Value metoden oversaetter chars til en int der giver den rigtige sortering.

Compare metoden bruger den til at sammenligne med via samme logik som du vil bruger, hvis du laver det i hovedet.
Avatar billede Mikker Praktikant
24. februar 2014 - 13:32 #12
Tak for hjælpen Arne. Den virker ikke helt som PHP's ksort. Det viser sig nemlig at ksort behandler "1" som et tal men "1a" som en streng.

Vi har i mellemtiden løst problemet ved at sætte ksort til SORT_STRING i PHP-scriptet, og så kan vi bruge ORDINAL i c# programmet.
Avatar billede Mikker Praktikant
24. marts 2014 - 08:12 #13
Lukkes
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester