J'ai en C # une String [] avec une liste de dossiers. Et je souhaite obtenir une sous-liste en fonction d'un critère. Par exemple:
var folder_list = new String[] {
"FOLDER0001",
"FOLDER0002",
"FOLDER0003",
"FOLDER0004",
"FOLDER0005"
};
et avec des paramètres (de et à), obtenez la sous-liste
Par exemple
de: 1
à: 3
Je souhaite obtenir String [] sub_list = {"FOLDER0001", FOLDER0002 "," FOLDER0003 "}
J'aimerais beaucoup pour le faire en utilisant linq.
5 Réponses :
Linq a le Skip pour omettre un certain nombre d'éléments dans une séquence et Take pour obtenir un certain nombre d'éléments. Le nombre que vous passez est le nombre d'éléments qui doivent être ignorés ou pris. Pour votre exemple:
public String[] SubArray(String[] array, int from, int to)
{
return array.Skip(from - 1).Take(to).ToArray();
}
Vous pouvez également généraliser cela. Puisque vous identifiez le premier élément avec 1 au lieu de 0 , la requête ressemblerait à ceci.
String[] subArray = folder_list.Take(3).ToArray();
Vous devez utiliser l'entrée entière pour reproduire la ou les chaînes correspondantes afin de rechercher les chaînes par plage.
var folder_list = new Dictionary<int,string> {
{ 1, "FOLDER0001"},
{ 2, "FOLDER0002"},
{ 3, "FOLDER0003"},
{ 4, "FOLDER0004"},
{ 5, "FOLDER0005"}
};
string[] GetSublist(int from, int to)
{
return folder_list
.Where
(
x => (x.Key >= from && x.Key <= to)
)
.Select( x => x.Value )
.ToArray();
}
Une autre option consiste à modifier la façon dont vous stockez les données pour le rendre plus consultable. Cela fonctionnerait légèrement mieux et serait plus résilient aux changements de formatage de la chaîne.
var folder_list = new String[] {
"FOLDER0001",
"FOLDER0002",
"FOLDER0003",
"FOLDER0004",
"FOLDER0005"
};
string[] GetSublist(int from, int to)
{
string start = "FOLDER" + from.ToString("D4");
string end = "FOLDER" + to.ToString("D4");
return folder_list.Where( x => (x >= start && x <= end)).ToArray();
}
Je suppose que FOLDER0001 à FOLDER0005 ne sont que des exemples de noms ... Votre code ne fonctionnerait pas si l'OP utilise les vrais noms de dossier ... Comme Users code >, Windows , Programmes .
Étant donné que l'OP recherche de 1 à 3 et obtient des dossiers avec ces valeurs dans les noms, je ne suis pas d'accord. Si l'intention était de récupérer par index, la sortie commencerait par FOLDER0002 en raison de l'indexation de base zéro. Mais je dirais que les deux réponses sont utiles.
Il veut une partie de la liste quel que soit le contenu ... De l'index de à l'index à . Voir la réponse @thatguy. Dans votre réponse si le contenu est mélangé, il retournera vide. par exemple. FOLDER0001 est dans l'index 4 et FOLDER0003 est dans l'index 0.
Puisque vous avez une plage à indexer, vous pouvez l'utiliser avec LINQ pour extraire les éléments:
var sl = new ArraySegment<string>(folder_list, from-1, to-from+1).ToArray();
Mais il serait beaucoup plus efficace d'utiliser ArraySegment à la place :
var sublist = Enumerable.Range(from-1, to-from+1).Select(i => folder_list[i]).ToArray();
Pour chaque nom de dossier, extrayez la clé, analysez la clé en un nombre et ne conservez que le nom du dossier si le nombre est compris entre min et max
En utilisant des méthodes d'extension. Voir méthodes d'extension démystifiées
IEnumerable<string> folderNames = ...
IEnumerable<string> folderNamesWithinRange = folderNames.WhereFolderKeyBetween(3, 7);
Utilisation :
public string ExtractKeyText(this string folderName)
{
// TODO: decide what to do if folderName == null
// depending on your actual folder name.
// is it really just "Folder00001" etc?
return folderName.SubString(6);
// if more difficult folderNames, consider using Regular Expressions
}
public IEnumerable<string> WhereFolderKeyBetween(
this IEnumerable<string> folders,
int minKey,
int maxKey)
{
// TODO: decide what to do if folders == null, or minKey > maxKey
return folders.Where(folder =>
{
string keyTxt = folder.ExtractKeyText();
return int.TryParse(keyTxt, out int key)
&& minKey <= key && key <= maxKey;
});
};
merci beaucoup à tous pour les réponses. Désolé pour mon anglais :(
Je ne peux pas expliquer correctement le problème ... En gros, je reçois une liste fixe de dossiers que je dois compresser et envoyer par e-mail. Comme le serveur SMTP a des limites de taille de pièce jointe, je suis obligé de diviser la liste des dossiers en plusieurs fichiers zip, mais les dossiers LIST peuvent ne pas être consécutifs. Exemple:
private String[] get_sub_list_folders(Int32 since, Int32 to, String[] folder_list)
{
var result = from folder in folder_list
where (Int32.Parse(folder.Substring(8)) >= since && Int32.Parse(folder.Substring(8)) <= to)
select folder;
return (result.ToList().ToArray());
}
private void zip_folders()
{
const String folder_pattern = "ABCDEF";
const Int32 folders_in_zip = 5000;
// Create list of all folder
String[] folder_list = Directory.GetDirectories(".", folder_pattern + "*", SearchOption.TopDirectoryOnly);
// Just in case order by name
Array.Sort(folder_list);
Int32 folders_count = folder_list.Length;
Int32 from = 1;
Int32 to = folders_in_zip;
// Build a chunk of the folder list
while (folders_count > 0)
{
// Make a subset fixed folder list
String[] zip_folders_list = get_sub_list_folders(from, to, folder_list);
// Build zip name
String zip_name = String.Format("{0}{1:0000000}_{0}{2:0000000}.zip", folder_pattern, from, to);
// Create zip
zip.create(zip_folders_list, zip_name);
from += folders_in_zip;
to += folders_in_zip;
folders_count -= folders_in_zip;
}
}
};
Donc, si je veux la liste de 1 à 3 je devrais obtenir "ABCDEF000001", "ABCDEF000002"
Ma solution est similaire à celle que j'implémente Harald et John Wu
var folder_list = new String[] {
"ABCDEF000001",
"ABCDEF000002",
"ABCDEF000004",
"ABCDEF000005",
"ABCDEF000007",
De rien. La prochaine fois, au lieu d'étendre votre question en donnant une réponse, pensez à modifier votre question. Il sera plus facile pour les gens de comprendre la question, et ce sera plus utile si à l'avenir les gens ont le même problème
var subList = folderList.Take (3) .ToArray ();?Ou mieux encore
.Skip (x) .Take (y) .ToArray ()@RubensFarias Vous devez ajouter un
Skippour obtenir ce que l'OP veut ... Les paramètres de et vers. DoncSkip (from) .Take (to)@LegacyCode Le problème est qu'ils veulent les index 0,1 et 2 mais spécifient 1-3 donc ce serait en fait
Skip (from-1) .Take (to-from + 1)en supposant que from is 1 et à est 3. De cette façon, cela fonctionnerait pour une base de 2 à 3 où vous voulez sauter 1 et prendre 2@juharr Bon point
Veuillez clarifier si cette question concerne l'obtention d'une plage d'éléments avec des indices ou si elle concerne le modèle "FOLDERxxxx".
Pourquoi voulez-vous être inefficace avec LINQ?