0
votes

LINQ fusion de 2 listes, conservation de la séquence et de l'origine

Ici, j'ai 2 listes du même type d'objet.

List mergedSet = [{old1, null}, {old2, new2}, {old3, new3}, {null, new4}];

Je souhaite fusionner les deux listes, en conservant également l'origine de la liste dont elles proviennent.

Le résultat attendu comme ci-dessous:

object = {id: xxx, ...} // attribute "id" is used to find the identical obj

List oldSet = [old1, old2, old3];
List newSet = [new2, new3, new4];

// old2 = {id= 2, result = 5, ...}
// new2 = {id= 2, result = 1, ...}
// expected result = {oldSet: old2; newSet: new2}

Je pense utiliser LINQ C # pour cela, mais coincé quelque part.

Veuillez conseiller.

Merci! :)


7 commentaires

déjà entendu parler de Dictionary? ou tableaux multidimensionnels?


Quel est le Type de mergedSet ? S'agit-il d'un List > ?


Je pense que le type de résultat peut être facultatif. Tant que je peux dire que cet élément provient de oldSet ou newSet, et combinez ceux avec le même identifiant. Merci à tous pour les indices


Ce serait génial si vous pouviez fournir un exemple reproductible minimal . Votre code, tel quel, ne se compile pas.


Les détails suivants manquent dans votre question pour fournir une réponse utile: (1) Les éléments oldSet et newSet auront-ils les éléments dans le même ordre, c'est-à-dire si L'identifiant des éléments dans le même index ne correspond pas. Est-il sûr de supposer que l'élément n'existe pas dans l'autre liste? (2) Quelle séquence doit être conservée? c'est-à-dire si les deux listes ont tout distinct et aucune correspondance pour aucun élément, quelle devrait être la sortie?


@MatJ (1) non, la séquence peut être aléatoire. et oui, si l'un n'existe pas dans l'autre liste, il est prudent de dire qu'il n'existe pas et de renvoyer un null. (2) la séquence d'objets dans la liste n'est pas importante. La "séquence" mentionnée en question fait référence à la liste de résultats finale, le premier élément proviendra de l'ancienSet, le second du newSet. J'espère que cela clarifie


Donnez un exemple de sortie requise pour deux listes distinctes. Comme list1 = [1,2,3,4,5], list2 = [10,20,30]. Quelle devrait être la sortie?


5 Réponses :


0
votes

Essayez quelque chose comme ceci:

            List<string> oldSet = new List<string>() {"old1", "old2", "old3"};
            List<string> newSet = new List<string>() {"new2", "new3", "new4"};

            var results = oldSet.Select((x,i) => new { oldSet = x, newSet = newSet[i]}).ToList();


1 commentaires

La question est un peu brisée, mais il semble qu'il ne se contente pas de les compresser, mais qu'il crée des paires en fonction des nombres dans les données.



1
votes

Voici un code qui fait ce que vous voulez en utilisant Linq. Il parcourt en gros toute l'ancienne liste et ajoute des paires à la liste fusionnée en recherchant des correspondances dans la nouvelle liste (et en ajoutant null comme deuxième élément si aucune correspondance n'a été trouvée). Ensuite, il parcourt les éléments restants dans la nouvelle liste et les ajoute avec null pour le premier élément. Il sélectionne un type dynamique avec deux propriétés: OldSet et NewSet , afin que vous sachiez d'où vient chaque élément.

Le code de fusion est simplement:

XXX


Ceci est basé sur la classe d'objets suivante:

foreach (var item in mergedSet)
{
    Console.WriteLine($"{item.NewSet},{item.OldSet}");
}

Nous créons nos listes:

List<Item> oldSet = new List<Item>
{
    new Item {id = 1, result = "old"},
    new Item {id = 2, result = "old"},
    new Item {id = 3, result = "old"},
};

List<Item> newSet = new List<Item>
{
    new Item {id = 2, result = "new"},
    new Item {id = 3, result = "new"},
    new Item {id = 4, result = "new"},
};

Exécutez le code de fusion (tout premier extrait de code), puis affichez les résultats:

class Item
{
    public int id { get; set; }
    public string result { get; set; }
    public override string ToString()
    {
        return $"{result}{id}";
    }
}

Sortie

! [entrez la description de l'image ici


3 commentaires

C'est beaucoup trop de code pour cette tâche ... Linq existe spécifiquement pour faire ce genre de chose. Il est inutile d'utiliser des tuples ici, quelques jointures ou une union feront très bien l'affaire.


Vous aviez raison, j'ai corrigé mon code, supprimé les commentaires non pertinents ... :)


@DrunkenCodeMonkey Cool. J'ai également corrigé le mien pour réduire le code de fusion de 2 lignes à une ligne (et j'ai également utilisé des types dynamiques) au cas où c'est pourquoi quelqu'un a voté contre.



0
votes

Vous pouvez quitter rejoindre les deux listes. J'ai modifié la réponse car vous devez en fait quitter deux fois la jointure, l'union et appliquer une sélection distincte pour obtenir les cas où oldSet = null et pas de doublons ...

    var mergedSet = (from o in oldSet
                     join n in newSet on o.id equals n.id into ns
                     from n in ns.DefaultIfEmpty()
                     select new { OldSet = o, NewSet = n })
                    .Union(from n in newSet
                           join o in oldSet on n.id equals o.id into os
                           from o in os.DefaultIfEmpty()
                           select new { OldSet = o, NewSet = n })
                    .Distinct();


0 commentaires

0
votes

Peut-être exagéré, mais si vous voulez vraiment utiliser LINQ

List<Item> oldSet = new List<Item>
{
    new Item {id = 1, result = "old"},
    new Item {id = 2, result = "old"},
    new Item {id = 3, result = "old"},
};

List<Item> newSet = new List<Item>
{
    new Item {id = 2, result = "new"},
    new Item {id = 3, result = "new"},
    new Item {id = 4, result = "new"},
};

var resultL = oldSet.GroupJoin(
          newSet, 
          o => o.id,
          n => n.id,
          (o,n) => new { Old = o, New = n })
    .SelectMany(
          n => n.New.DefaultIfEmpty(),
          (o,n) => new Tuple<Item,Item>(o.Old,n));


 var resultR= newSet.GroupJoin(
          oldSet, 
          n => n.id,
          o=> o.id,
          (n,o) => new { Old = o, New = n })
    .SelectMany(
          o=> o.Old.DefaultIfEmpty(),
          (n,o) => new Tuple<Item,Item>(o,n.New));

var result = resultL.Union(resultR).Distinct();


0 commentaires

0
votes

Dans ce cas, vous devez utiliser deux GroupJoin et l ' Union les résultats. Regardez le code suivant:

var res1 = oldSet.GroupJoin(newSet, o => o, k => k, (x, y) => { var yy = y.FirstOrDefault(); return new { X = x, Y = yy }; });
var res2 = newSet.GroupJoin(oldSet, o => o, k => k, (x, y) => { var yy = y.FirstOrDefault(); return new { X = yy, Y = x }; });
var result = res1.Union(res2).ToList();// Your result is here

 entrez la description de l'image ici


0 commentaires