9
votes

C # Liste de tri basée sur une autre liste

J'ai une classe qui a une liste multiple contenue en elle. C'est fondamentalement une table stockée avec chaque colonne sous forme de liste . Chaque colonne ne contient pas le même type. Chaque liste est également la même longueur (a le même nombre d'éléments).

Par exemple: P>

J'ai 3 liste objets; Une liste, deux liste et trois liste. P>

//Not syntactically correct
List<DateTime> one = new List...{4/12/2010, 4/9/2006, 4/13/2008};
List<double> two = new List...{24.5, 56.2, 47.4};
List<string> three = new List...{"B", "K", "Z"};


0 commentaires

7 Réponses :


2
votes

Vous devez d'abord créer un objet de données pour tout contenir. XXX PRE>

Ensuite, vous pouvez trier comme ceci. P>

var l = new List<Data>();
l.Sort(
    (a, b) =>
    {
        var r = a.DateTime.CompareTo(b);
        if (r == 0)
        {
            r = a.Int32.CompareTo(b);
            if (r == 0)
            {
                r = a.String.CompareTo(b);
            }
        }
        return r;
    }
);


3 commentaires

Je vais donc itérer à travers chaque liste et créer une structure de données à partir des données. Ensuite, je trie les données, puis je le remette dans les listes. Cela a du sens, mais cela ne semble pas être efficace. Cela travaillera au moins et c'est mieux que ce que j'ai actuellement. Merci. EDIT: Je ne sais pas nécessairement qu'il y a 3 articles, donc je ne peux pas utiliser une structure. Une liste pourrait probablement fonctionner mais devrais-je m'inquiéter de casting sur le gros genre?


@John - Recevez-vous ces listes d'une source incontrôlable?


Ouais, la liste <> Les objets que je reçois ne peuvent pas être changés; Ils peuvent cependant être triés en place.



7
votes

J'ai géré cette conception dans le passé en gardant ou en créant une liste d'index distincte. Vous triez d'abord la liste d'index, puis utilisez-la pour trier (ou simplement accéder à) les autres listes. Vous pouvez le faire en créant un ICOMPARER personnalisé pour la liste d'index. Ce que vous faites à l'intérieur de cet icomparer est de comparer en fonction des index dans la liste des clés. En d'autres termes, vous triez indirectement la liste d'index. Quelque chose comme: xxx

Vous triez la liste d'index en fonction des valeurs de la liste des touches. Ensuite, vous pouvez utiliser cette liste de clés triée pour commander les autres listes. Si cela n'est pas clair, je vais essayer d'ajouter un exemple plus complet lorsque je suis dans une situation de poster une.


1 commentaires

+1. C'est une excellente approche. J'ai exactement ce genre de "liste indirecte" dans ma bibliothèque personnelle; C'est utile pour beaucoup de choses. Exemple de code ici .



1
votes

Utilisation de tableaux génériques, cela peut être un peu lourd.

Une alternative utilise le array.sort () méthode qui prend une gamme de clés et une gamme de valeurs pour trier. Il trie d'abord le tableau de la clé en ordre croissant et veille à ce que la matrice de valeurs soit réorganisée pour correspondre à cet ordre de tri.

Si vous êtes prêt à encourager le coût de la conversion de votre liste s sur les tableaux (puis de retour), vous pouvez profiter de cette méthode.

Alternativement, vous pouvez utiliser LINQ pour combiner les valeurs de plusieurs tableaux en un seul type anonyme à l'aide de zip () , triez la liste des types anonymes à l'aide du champ Clé, puis divisez-le à cet effet Réparez des tableaux.

Si vous voulez faire cela en place, vous devrez écrire un comparateur personnalisé et créer un tableau d'index distinct pour maintenir la nouvelle commande d'éléments.


0 commentaires

3
votes

Je suis désolé de dire, mais cela ressemble à un mauvais design. Surtout parce que la liste ne garantit pas l'ordre des éléments avant d'avoir appelé l'une des opérations de tri (donc vous avez un problème lors de l'insertion):

de MSDN :

La liste n'est pas garantie trié. Vous devez trier la liste avant d'effectuer des opérations (telles que Binaryschearch) qui nécessite la liste être trié.

Dans de nombreux cas, vous ne rencontrerez pas de problèmes en fonction de cela, mais vous pourriez, et si vous le faites, cela pourrait être un bug très dur de suivre. Par exemple, je pense que la mise en œuvre actuelle de la liste maintient l'ordre d'insertion jusqu'à ce que le tri soit appelé, mais cela pourrait changer à l'avenir.

J'envisagerai sérieusement refactoring d'utiliser une autre structure de données . Si vous souhaitez toujours mettre en œuvre le tri basé sur cette structure de données, je créerais un objet temporaire (peut-être utiliser un type anonyme), trier cela et recréer les listes ( Voir cette excellente réponse pour une explication de la manière).


4 commentaires

Je suis d'accord il y a de meilleurs conceptions. Les principales situations dans lesquelles je rencontrais dans ce passé, c'est où je n'avais pas la propriété des tableaux d'origine et ils étaient trop gros pour faire des copies séparées. Si vous êtes propriétaire, tout cela signifie que vous en prenez une classe ou une structure icomparable avec toutes les données.


Je ne peux pas vraiment changer cela mais voici la demande. Fondamentalement, la liste <> Les objets contiennent des données et que les données sont transmises aux fonctions mathématiques. Les fonctions mathématiques transmettent ensuite le résultat et sont annexées à la classe de table. Serait-il préférable de stocker ce truc Row-Wise et de projeter les colonnes à l'aide de LINQ? Cela rend l'insert beaucoup plus compliqué cependant.


Oui, je pense certainement qu'il serait préférable de stocker la ligne de rangée. Je ne vois pas comment les insertions seraient plus compliquées par cela; Mais là encore, je ne connais pas la totalité de l'application et de vos contraintes.


Autant que je sache la liste ne garantit pas l'élément à trier, mais il garantit une commande d'élément en fonction de l'ordre d'insertion (voir Ici par exemple), il n'y a donc pas de strictement besoin de refactoring.



1
votes

J'espère que cela pourrait aider:

one = one.Sort(delegate(DateTime d1, DateTime d2)
{
    return Convert.ToDateTime(d2).CompareTo(Convert.ToDateTime(d1));
});


0 commentaires

2
votes

J'ai écrit un algorithme de tri qui correspond à Nito.Linq (non encore sorti). Il utilise un AMIQUESTORT SIMPLEMENTALE POUR TRIER LES LISTES ET CONTENIR Nombre de listes associées en Sync. Le code source commence ici, dans le ilist .sort Code> Méthode d'extension.

Alternativement, si la copie des données n'est pas une préoccupation énorme, vous pouvez le projeter dans une requête LINQ à l'aide de l'opérateur ZIP (nécessite .NET 4.0 ou RX), commandez-la et Ensuite, tirez chaque résultat: P>

List<DateTime> one = ...;
List<double> two = ...;
List<string> three = ...;
var combined = one.Zip(two, (first, second) => new { first, second })
    .Zip(three, (pair, third) => new { pair.first, pair.second, third });
var ordered = combined.OrderBy(x => x.first);
var orderedOne = ordered.Select(x => x.first);
var orderedTwo = ordered.Select(x => x.second);
var orderedThree = ordered.Select(x => x.third);


1 commentaires

Voici la mise à jour code source lien.



4
votes

Voici un moyen de le faire à l'aide de Linq et de projections. La première requête génère un tableau avec les index d'origine réorganisés par les valeurs DateTime; Dans votre exemple, le tableau de la nouvelle commande aurait des membres:

{4/9/2006, 1}, {4/13/2008, 2}, {4/12/2010, 0} code> p>

Le second ensemble d'instructions génère de nouvelles listes en cueillant des éléments à l'aide des index de réorganisation (en d'autres termes, les éléments 1, 2 et 0, dans cet ordre). P>

var newOrdering = one
    .Select((dateTime, index) => new { dateTime, index })
    .OrderBy(item => item.dateTime)
    .ToArray();

// now, order each list
one = newOrdering.Select(item => one[item.index]).ToList();
two = newOrdering.Select(item => two[item.index]).ToList();
three = newOrdering.Select(item => three[item.index]).ToList();


2 commentaires

J'aime cette solution, mais est-ce efficace? Je ne sais pas autant de choses sur la performance de projection;


Qu'une seule façon de le savoir - :-)