J'ai une requête qui renvoie plusieurs lignes. La première ligne est le nom et la deuxième ligne est la valeur réelle. Le résultat final est de prendre un nom spécifique et d'ajouter la valeur à une ligne datable.
Code:
var data = query.ToList();
var obj = data.Select((item, index) =>
{
if (index < data.Count - 1 && index % 2 == 0)
return new KeyValuePair<string, string>(item, data[index + 1]);
return new KeyValuePair<string, string>(null, null);
}).Where(x => x.Key != null);
Résultat
string clientname = value[x]; or something similar
4 Réponses :
Vous pouvez essayer quelque chose comme ceci:
Dictionary<string, string> map = new Dictionary<string, string>();
for (int idx = 0; idx < data.Count - 1; idx += 2)
{
map[data[idx]] = data[idx + 1];
}
À la place des données dans le code ci-dessus, vous pouvez utiliser votre variable: query
C'est manifestement déroutant, donc un la manière la plus simple est:
List<string> data = new List<string>() { "Client Name", "Siemens", "Client ID", "7000002", "File Status", "Successful" };
var obj = data.Select((item, index) =>
{
if (index < data.Count - 1 && index % 2 == 0)
return new KeyValuePair<string, string>(item, data[index + 1]);
return new KeyValuePair<string, string>(null, null);
}).Where(x => x.Key != null);
En regardant la variable obj sa valeur null pour la clé et la valeur.
Oui, ce sont les cas que nous ne voulons pas. La sélection s'exécutera pour chaque index de la liste. Nous voulons le dictionnaire où l'élément à 0 est la clé et 1 est la valeur, 2 est la clé et 3 est la valeur. Ainsi, l'élément null null représente les cas où l'index Odd essaie d'être clé. Vous pouvez également le remplacer par une simple boucle for.
Cette solution ne fonctionne pas. Toutes les propriétés ne sont pas à 2 lignes.
@jdweng - Cela fonctionne si vous avez pair ou impair - quel que soit le nombre d'éléments. Vous résolvez un mauvais problème. Notez que OP ne veut pas que la sortie logger.Info soit analysée.
Vous avez besoin d'un accès aléatoire, donc votre première étape devrait être de réaliser les résultats et de les stocker en mémoire.
var dictionary = Enumerable.Range(0, list.Count / 2)
.ToDictionary
(
i => list[i * 2],
i => list[i * 2 + 1]
);
Une fois que vous avez cela, vous pouvez accéder via un index et assembler les lignes dont vous avez besoin .
var list = query.ToList();
C'est bon - :)
Cette solution ne fonctionne pas. Toutes les propriétés ne sont pas à 2 lignes.
Vous vous trompez @jdweng
Regardez mes résultats. Il analyse du texte. Cela n'a-t-il pas beaucoup plus de sens que les autres solutions: clé: date de téléchargement, valeur: 03-mars-2020, succès, 7
J'analyse des fichiers texte depuis plus de 45 ans. Le code ci-dessous fonctionne lorsque chaque élément contient 2 lignes ou plus. Pas comme l'autre solution. L'utilisation du mod 2 ne fonctionnera pas dans ce cas (ou divisée par 2)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = @"c:\temp\test.txt";
static void Main(string[] args)
{
StreamReader reader = new StreamReader(FILENAME);
string line = "";
Dictionary<string, string> dict = new Dictionary<string, string>();
string buffer = "";
string key = "";
Boolean first = true;
while ((line = reader.ReadLine()) != null)
{
line = line.Trim();
if (line.Length > 0)
{
string[] splitLine = line.Split(new string[] { "INFO" }, StringSplitOptions.None).ToArray();
if (splitLine[1].Contains(":"))
{
if (!first)
{
dict.Add(key, buffer);
}
key = splitLine[1].Trim(new char[] { ' ', ':' });
buffer = "";
first = false;
}
else
{
if (buffer == string.Empty)
{
buffer = splitLine[1].Trim();
}
else
{
buffer += "," + splitLine[1].Trim();
}
}
}
}
dict.Add(key, buffer);
foreach (KeyValuePair<string, string> pair in dict)
{
Console.WriteLine("Key '{0}' : Value '{1}'", pair.Key, pair.Value);
}
Console.ReadLine();
}
}
}
Eh bien, vous vous êtes trompé de question, les lignes sous la section Résultat avec Horodatage et INFo et message texte sont la sortie coz OP utilise un cadre de journalisation "Note: logger.Info (" {0} ", cell);". Vous résolvez donc un mauvais problème. Il analyse une source HTML et crée cette variable de requête. Dont il veut être converti en dictionnaire.
Regardez mes résultats. Il analyse du texte. Cela n'a-t-il pas beaucoup plus de sens que les autres solutions: clé: date de téléchargement, valeur: 03-mars-2020, succès, 7
:( Vous devrez peut-être relire la question. Le texte que vous essayez d'analyser est la sortie de la boucle d'OP où est dit Logger.Info - qui est Log4Net ou un cadre similaire écrivant un message de journal. La question qu'il a est avant même le code atteint cette boucle. Si vous l'obtenez cette fois, super, si vous ne le faites pas. Attendez qu'OP (qui a déjà trouvé sa solution) revienne pour vous remercier.
Je pense qu'il ressort clairement de la question que l'entrée pour cette conversion n'est pas le texte du journal, mais une requête . Donc, bien que cette réponse ne soit pas fausse, elle rend probablement les choses plus difficiles que nécessaire. Bien que, je pense qu'une partie de la confusion provient du fait que certaines des lignes de nom ne se terminent pas par un point-virgule. Ainsi, y a-t-il deux paires, File Status = Successful et Sent = 7 ? Ou une paire, File Status = Successful, Sent, 7 ? À part parler de «première» et «deuxième» lignes (donc, vraisemblablement, en alternance), la question ne dit pas, donc cette interprétation n'est pas déraisonnable à cet égard.
J'ai analysé 1000 fichiers texte au fil des ans. Ainsi, lorsqu'un OP poste un problème d'analyse, j'utilise mon expérience et je ne fais pas nécessairement exactement ce que l'OP demande. Je fais ce qui est le plus logique sur la base des données d'entrée et de l'expérience passée.
Puisque tout ce dont vous avez besoin, ce sont des chaînes consécutives - et non la collection entière - pour produire un pair , vous pouvez énumérer manuellement votre requête deux à la fois en utilisant un méthode iterator à yield résultats dès qu'ils sont disponibles ...
[snip]
from cell in row.SelectNodes("th|td")
let cellText = cell.InnerText.ToString()
where !string.IsNullOrEmpty(cellText)
&& cellText != "File Summary"
&& cellText != "Payment Instructions"
&& cellText != "Number"
select cell.InnerText;// This should probably be cellText as well
Vous l'appelleriez ainsi ...
static List<KeyValuePair<string, string>> ExtractPairsByAggregation(IEnumerable<string> items)
{
return items
// Aggregate() doesn't have an overload that provides the index,
// so package it together with each item in a ValueTuple using Select()
.Select((item, index) => (item, index))
.Aggregate(
// Storage for both intermediate and final results
new List<KeyValuePair<string, string>>(),
(list, current) => {
if (current.index % 2 == 0) // Even items are a name
{
KeyValuePair<string, string> newPair = new KeyValuePair<string, string>(
current.item, "<none>"
);
// Add a partial pair as soon as it's encountered
// so it's still present in the results even if
// this is the last item in the sequence
list.Add(newPair);
}
else // Odd items are a value
{
// The last pair in the list is the corresponding partial pair
int pairIndex = list.Count - 1;
KeyValuePair<string, string> oldPair = list[pairIndex];
// KeyValuePair<> is immutable, so recreate it now that we have the value
KeyValuePair<string, string> newPair = new KeyValuePair<string, string>(
oldPair.Key, current.item
);
list[pairIndex] = newPair;
}
// Return the same list so it is available for the
// next item in the sequence and as the final result
return list;
}
);
}
... qui produit une sortie comme celle-ci ...
Extracting 20 input lines:
[Client Name:, Siemens]
[Client ID:, 7000002]
[Batch File Name:, 6030001030-20200303-00005470]
[File Status:, Successful]
[Sent, 7]
[Batch File ID:, 0008615020]
[Date Uploaded:, 03-Mar-2020]
[Successful, 7]
[Creator:, STP-SIEMENSCORPOR]
[Failed, 0]
Extracting 19 input lines:
[Client Name:, Siemens]
[Client ID:, 7000002]
[Batch File Name:, 6030001030-20200303-00005470]
[File Status:, Successful]
[Sent, 7]
[Batch File ID:, 0008615020]
[Date Uploaded:, 03-Mar-2020]
[Successful, 7]
[Creator:, STP-SIEMENSCORPOR]
[Failed, <none>]
Notez qu'il produit toujours des résultats raisonnables sortie dans le second cas avec un nombre impair de lignes.
Une alternative LINQ qui ne nécessite également qu'un IEnumerable est d'utiliser le Méthode Aggregate () . Cela prend un délégué auquel est passé chaque élément de la séquence d'entrée et un accumulateur (c'est-à-dire liste ) que vous utilisez pour stocker les résultats jusqu'à ce point ...
using System;
using System.Collections.Generic;
using System.Linq;
namespace SO60748447
{
class Program
{
private const string InputText = @"
Client Name:
Siemens
Client ID:
7000002
Batch File Name:
6030001030-20200303-00005470
File Status:
Successful
Sent
7
Batch File ID:
0008615020
Date Uploaded:
03-Mar-2020
Successful
7
Creator:
STP-SIEMENSCORPOR
Failed
0";
static void Main()
{
string[] inputLines = InputText.Trim().Split("\r\n");
IEnumerable<string>[] testQueries = new IEnumerable<string>[] {
inputLines,
inputLines.Take(inputLines.Length - 1)
};
foreach (IEnumerable<string> query in testQueries)
{
Console.WriteLine($"Extracting {query.Count()} input lines:");
foreach (KeyValuePair<string, string> pair in ExtractPairsByEnumeration(query))
Console.WriteLine($"\t{pair}");
Console.WriteLine();
}
}
}
}
ce que vous vouliez dire par clientname = valeur [x] ???
sélectionnez un nouveau KeyValuePair (..., ...) fonctionne?J'ai besoin de convertir les valeurs de ligne paires en chaînes individuelles à utiliser comme valeurs de colonne dans une table de données. Par exemple, dt.column.add ("clientname") puis définissez cette valeur.