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?
3 Réponses :
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;
}
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
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;
}
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.
Vous n'avez pas mentionné ce qui se passe lorsqu'il y a deux groupes d'identifiants consécutifs. Par exemple,
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);
}
Où 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
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);
}
Merci pour cette réponse géniale.
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é