Linq Aggregate tipos complexos em uma corda
-
19-09-2019 - |
Pergunta
Eu vi o exemplo simples da função .net Aggregate trabalhando assim:
string[] words = { "one", "two", "three" };
var res = words.Aggregate((current, next) => current + ", " + next);
Console.WriteLine(res);
Como é que a função 'agregado' ser usado se você deseja agregar tipos mais complexos? Por exemplo: uma classe com 2 propriedades como 'chave' e 'valor' e você quer a saída como esta:
"MyAge: 33, MyHeight: 1.75, MyWeight:90"
Solução
Você tem duas opções:
-
Project para um
string
e depois agregado:var values = new[] { new { Key = "MyAge", Value = 33.0 }, new { Key = "MyHeight", Value = 1.75 }, new { Key = "MyWeight", Value = 90.0 } }; var res1 = values.Select(x => string.Format("{0}:{1}", x.Key, x.Value)) .Aggregate((current, next) => current + ", " + next); Console.WriteLine(res1);
Isto tem a vantagem de usar o primeiro elemento
string
como a semente (sem prefixado ""), mas irá consumir mais memória para as cordas criadas no processo. -
Use uma sobrecarga agregado que aceita uma semente, talvez um
StringBuilder
:var res2 = values.Aggregate(new StringBuilder(), (current, next) => current.AppendFormat(", {0}:{1}", next.Key, next.Value), sb => sb.Length > 2 ? sb.Remove(0, 2).ToString() : ""); Console.WriteLine(res2);
O segundo delegado converte nosso
StringBuilder
em umstring,
utilizando o condicional para aparar a partida "".
Outras dicas
Aggregate tem 3 sobrecargas, para que você possa usar o que tem tipo diferente de acumular os itens que você está enumerando.
Você precisaria passar em um valor de semente (sua classe personalizada), e um método para adicionar fundir a semente com um valor. Exemplo:
MyObj[] vals = new [] { new MyObj(1,100), new MyObj(2,200), ... };
MySum result = vals.Aggregate<MyObj, MySum>(new MySum(),
(sum, val) =>
{
sum.Sum1 += val.V1;
sum.Sum2 += val.V2;
return sum;
}
A função Aggregate aceita um parâmetro delegado. Você define o comportamento desejado mudando o delegado.
var res = data.Aggregate((current, next) => current + ", " + next.Key + ": " + next.Value);
Ou uso String.Join ():
var values = new[] {
new { Key = "MyAge", Value = 33.0 },
new { Key = "MyHeight", Value = 1.75 },
new { Key = "MyWeight", Value = 90.0 }
};
var res = string.Join(", ", values.Select(item => $"{item.Key}: {item.Value}"));
Console.WriteLine(res);