1
votes

Comment obtenir la liste des éléments adjacents avec le même nom uniquement

J'ai une liste qui ressemble à ceci:

public static void main {
   int itemToBeSearched = 4;

   List<Item> list = new List<Item>();
        list.Add(new Item { Id = 1, Name = "name1" });
        list.Add(new Item { Id = 2, Name = "name2" });
        list.Add(new Item { Id = 3, Name = "name1" });
        list.Add(new Item { Id = 4, Name = "name1" });
        list.Add(new Item { Id = 5, Name = "name1" });
        list.Add(new Item { Id = 6, Name = "name3" });
        list.Add(new Item { Id = 7, Name = "name1" });

    //I need help in getting a return here
    var subList = GetAdjacentList(list, itemToBeSearched);
}

public List<Item> GetAdjacentList(List list, int itemToBeSearched)
{
    //Need help with the logic or linq here that would give a return such as
    return List<Item> list = new List<Item>();
        list.Add(new Item { Id = 3, Name = "name1" });
        list.Add(new Item { Id = 4, Name = "name1" });
        list.Add(new Item { Id = 5, Name = "name1" });
}

Et la sortie souhaitée devrait être: une sous-liste de celle-ci qui ne contient que Item2, Item3 et Item4 .

Je voulais seulement un retour d'une sous-liste contenant uniquement Item3, Item4 et Item5 parce qu'ils sont adjacents l'un à l'autre avec le même nom qui est name1 retour .

Item1

et Item7 ne sont pas inclus même s'ils portent le nom name1 car ils ne sont pas proches du groupe adjacent. p>

Quelqu'un peut-il m'aider à résoudre ce problème en utilisant Linq ou autrement?


4 commentaires

Veuillez fournir le code réel de votre liste.


@John J'ai ajouté le code sur ma liste. Merci.


L'ID est-il unique?


@John Oui, l'identifiant est unique. J'ai ajouté du code pour plus de clarté


3 Réponses :


2
votes

Il y a probablement une façon plus simple de le faire, mais c'est ce que j'ai trouvé. Il n'utilise aucun LINQ, mais il maintient l'ordre des éléments de la liste (en supposant que c'est important).

public static List<Item> GetAdjacentList(List<Item> list, int itemToBeSearched)
{
    List<Item> result = new List<Item>();
    // find the index of the item we're searching for
    int itemIdx = list.FindIndex(i => i.Id == itemToBeSearched);
    if (itemIdx == -1)
    {
        return result; // not found, return empty list
    }

    // store the item for comparisons
    Item item = list[itemIdx];

    // loop backwards starting from the current item ann going to the 0th element
    for (int i = itemIdx; i >= 0; --i)
    {
        // if this item is the search item, or the name matches, add it to the list
        if (i == itemIdx || list[i].Name == item.Name)
        {
            result.Add(list[i]);
        }
        else
        {
            // exit the loop as we've run out of items with the same name
            break;
        }
    }

    if (result.Count > 0)
    {
        result.Reverse(); // we've added items in reverse order, so reverse the list
    }

    // loop through all the items from the next item to the end of the list
    for (int i = itemIdx + 1; i < list.Count; ++i)
    {
        // if the name matches add it to the result list
        if (list[i].Name == item.Name)
        {
            result.Add(list[i]);
        }
        else
        {
            // we've reached the end of matching names so break
            break;
        }
    }
    // return the result
    return result;
}


3 commentaires

Merci beaucoup. Ça fonctionne. Sauf si je mets itemToBeSearched à 1. La liste retourne vide.


Je pense que je l'ai réparé, même si je ne suis pas sur mon ordinateur pour le tester. J'ai changé i> 0 en i> = 0


Ouais, je peux le voir. Merci



0
votes

Vous pouvez utiliser de simples boucles arrière et avant pour trouver les éléments adjacents d'un nom spécifique dans une plage donnée et renvoyer une List avec le même ordre des éléments:

The adjacent items of ID 1 => 1       (name1)
The adjacent items of ID 2 => 2       (name2)
The adjacent items of ID 3 => 3, 4    (name1)
The adjacent items of ID 4 => 3, 4, 5 (name1)
The adjacent items of ID 5 => 4, 5    (name1)
The adjacent items of ID 6 => 6       (name3)
The adjacent items of ID 7 => 7       (name1)

Les sorties de l'exemple donné de List ( rang = 1 ):

public List<Item> GetAdjacentList(List<Item> list, int itemToBeSearched, int range)
{
    var result = new List<Item>();
    var tar = list.FirstOrDefault(x => x.Id == itemToBeSearched);

    if (tar == null) return result;

    var indx = list.IndexOf(tar);
            
    for (var i = indx - 1; i >= (indx - range); i--)
    {
        if (i >= 0 && list[i].Name.Equals(tar.Name, 
            StringComparison.CurrentCultureIgnoreCase))
            result.Insert(0, list[i]);
        else
            break;
    }

    result.Add(list[indx]);

    for (var i = indx + 1; i <= (indx + range) ; i++)
    {
        if (i < list.Count() && list[i].Name.Equals(tar.Name, 
            StringComparison.CurrentCultureIgnoreCase))
            result.Add(list[i]);
        else
            break;
    }
    return result;
}


2 commentaires

merci d'avoir répondu. Cela fonctionne-t-il uniquement avec les plages +1 et -1? Est-il possible de rendre cette plage dynamique? Par exemple, s'il y a 4 éléments adjacents avec le même nom?


@PaulaKristin Le nouveau fait. Passez simplement la plage requise dans le troisième paramètre.



1
votes

Vous n'avez pas mentionné ce qui se passe lorsqu'il y a deux groupes d'identifiants consécutifs. Par exemple,

 entrez la description de l'image ici

Cas 1 : Récupérer en deux groupes séparés

En supposant que vous puissiez comme pour récupérer les deux îlots de groupes en tant que collections séparées, vous pouvez modifier la méthode comme suit.

public IEnumerable<Item> GetAdjacentList(List<Item> list, int itemToBeSearched)
{
    var nameToBeSearched = list.First(x=>x.Id==itemToBeSearched).Name;
    return list.Where(x=>x.Name.Equals(nameToBeSearched))
                .GroupWhile((x, y) => y.Id - x.Id == 1)
                .Where(x=>x.Count()>1).SelectMany(x=>x);
}

GroupWhile est défini comme

public static class Extensions
{
    public static IEnumerable<IEnumerable<T>> GroupWhile<T>(this IEnumerable<T> seq, Func<T,T,bool> condition)
    {
        T prev = seq.First();
        List<T> list = new List<T>() { prev };
    
        foreach(T item in seq.Skip(1))
        {
            if(condition(prev,item)==false)
            {
                yield return list;
                list = new List<T>();
            }
            list.Add(item);
            prev = item;
        }
    
        yield return list;
    }
}

Sortie

 entrez la description de l'image ici

Cas 2 : Récupérer en tant que groupe fusionné unique

Si vous souhaitez que les deux groupes d'îles soient fusionnés en un seul, vous pouvez modifier la méthode ci-dessus comme

public IEnumerable<IEnumerable<Item>> GetAdjacentList(List<Item> list, int itemToBeSearched)
{
    var nameToBeSearched = list.First(x=>x.Id==itemToBeSearched).Name;
    return list.Where(x=>x.Name.Equals(nameToBeSearched))
                .GroupWhile((x, y) => y.Id - x.Id == 1)
                .Where(x=>x.Count()>1);
}


1 commentaires

Merci pour cette réponse géniale.