0
votes

Comment obtenir une liste de chaînes en utilisant linq?

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.


7 commentaires

var subList = folderList.Take (3) .ToArray (); ?


Ou mieux encore .Skip (x) .Take (y) .ToArray ()


@RubensFarias Vous devez ajouter un Skip pour obtenir ce que l'OP veut ... Les paramètres de et vers. Donc Skip (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?


5 Réponses :


2
votes

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();


0 commentaires

1
votes

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();
}


3 commentaires

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 , 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.



0
votes

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();


0 commentaires

1
votes

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;
    });
};
        


0 commentaires

0
votes

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",


1 commentaires

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