Использование LINQ в массиве строк для повышения эффективности C#
У меня есть строка уравнения, и когда я делю ее по своему шаблону, я получаю следующий массив строк.
string[] equationList = {"code1","+","code2","-","code3"};
Затем из этого я создаю список, который содержит только коды.
List<string> codeList = {"code1","code2","code3"};
Затем существующий код перебирает codeList и извлекает значение каждого кода и заменяет значение в уравнении уравнения приведенным ниже кодом.
foreach (var code in codeList ){
var codeVal = GetCodeValue(code);
for (var i = 0; i < equationList.Length; i++){
if (!equationList[i].Equals(code,StringComparison.InvariantCultureIgnoreCase)) continue;
equationList[i] = codeVal;
break;
}
}
Я пытаюсь повысить эффективность и считаю, что могу избавиться от цикла for в foreach с помощью linq.
Мой вопрос: будет ли лучше, если я сделаю это с точки зрения ускорения процесса?
Если да, то можете ли вы помочь с оператором linq?
3 ответа
Прежде чем перейти к LINQ..., который не решает проблем, которые вы описали, давайте рассмотрим логику, которая у вас есть.
- Мы разбиваем строку с помощью "шаблона". Как?
- Затем мы создаем новый список кодов. Как?
- Затем мы перебираем эти коды и декодируем их. Как?
- Но так как мы забыли отслеживать, откуда появился этот код, мы теперь перебираем уравнение листинга (который представляет собой массив, а не
List<T>
) подставить результаты.
Кажется, немного запутанным для меня.
Может быть, более простое решение будет:
- Взять в
string
, и вернутьсяIEnumerable<string>
слов (похоже на то, что вы делаете сейчас). - Взять в
IEnumerable<string>
слов, и вернутьIEnumerable<?>
ценностей.
То есть с помощью этого второго шага переберите строки и просто верните значение, которое вы хотите вернуть - вместо того, чтобы пытаться извлечь определенные значения, проанализировать их, а затем вставить их обратно в коллекцию.
//Ideally we return something more specific eg, IEnumerable<Tokens>
public IEnumerable<string> ParseEquation(IEnumerable<string> words)
{
foreach (var word in words)
{
if (IsOperator(word)) yield return ToOperator(word);
else if (IsCode(word)) yield return ToCode(word);
else ...;
}
}
Это очень похоже на оператор выбора LINQ... если бы я настоял, я бы предложил написать что-то вроде этого:
var tokens = equationList.Select(ToToken);
...
public Token ToToken(string word)
{
if (IsOperator(word)) return ToOperator(word);
else if (IsCode(word)) return ToCode(word);
else ...;
}
Если GetCodeValue(код) этого еще не сделал, я полагаю, что он, возможно, мог бы использовать своего рода кеширование / словарь в своей реализации - хотя специфика диктует это.
Преимущества этого подхода в том, что он гибкий (мы можем легко добавить больше этапов обработки), простой для отслеживания (мы вводим эти значения и получаем их в результате, без изменения состояния) и легко пишется. Это также разбивает проблему на милые маленькие кусочки, которые решают свою собственную задачу, что очень поможет при попытках рефакторинга или при обнаружении проблем и проблем с производительностью.
Если ваш массив всегда чередующийся кодекс, то оператор этого LINQ должен делать то, что вы хотите:
string[] equationList = { "code1", "+", "code2", "-", "code3" };
var processedList = equationList.Select((s,j) => (j % 2 == 1) ? s :GetCodeValue(s)).ToArray();
Вам нужно будет проверить, быстрее ли это
Я думаю, что самым быстрым решением будет это:
var codeCache = new Dictionary<string, string>();
for (var i = equationList.Length - 1; i >= 0; --i)
{
var item = equationList[i];
if (! < item is valid >) // you know this because you created the codeList
continue;
string codeVal;
if (!codeCache.TryGetValue(item, out codeVal))
{
codeVal = GetCodeValue(item);
codeCache.Add(item, codeVal);
}
equationList[i] = codeVal;
}
Вам не нужен codeList
, Если каждый код уникален, вы можете удалить codeCace
,