2009-11-30 7 views
3

J'ai une boucle:Agrégation dans la boucle foreach

<% foreach (User usedBy in discountDto.UsedBy) 
    { %> 
    <%=usedBy.FullName%><br /> 
<% } %> 

qui produit souvent plusieurs lignes avec le même nom:

Bob Smith 
Mark Thomas 
Mark Thomas 
Steve Jones 

je voudrais regrouper les multiples lignes à une seule ligne suivie par un nombre entier représentant le nombre de fois que le nom a eu lieu:

Bob Smith 
Mark Thomas (2) 
Steve Jones 

Répondre

9

S'il vous plaît excuser la mise en forme - mauvais outils "à la main" ...

foreach (User usedBy in discountDto.UsedBy.GroupBy(x => x.FullName)) 
{ 
    var count = usedBy.Count(); 
    %><%=usedBy.Key%><% 
     if(count>1) %><%=" (" + count + ")"%><% 
    %><br /> 
<% } %> 
+0

Non OP ici, mais intéressé par réponse. Je reçois une exception de transtypage invalide sur la ligne foreach. "Impossible de convertir un objet de type" Grouping [System.String, Nom_Solution.User] "pour taper" Nom_Solution.User "." Où vais-je mal? – jammus

+1

Je crois que le GroupBy ne renverra pas un utilisateur, mais plutôt un IGrouping . Vous avez juste besoin de changer le foreach (Utilisateur Usedby dans discountDto.UsedBy.GroupBy (x => x.FullName)) à foreach (IGrouping Usedby dans discountDto.UsedBy.GroupBy (x => x. FullName)) –

+0

Essayez de changer la ligne foreach à: 'foreach (var usedBy en discountDto.UsedBy.GroupBy (x => x.FullName))' – Charlino

1
var aggregatedUsers=from users in discountDto.UsedBy 
            group user by user.FullName into result 
            select new 
             { 
              User=result.Key, 
              Count= result.Count(), 
             }; 
+0

Vous n'avez pas vraiment besoin ' dans ... sélectionnez »ici. Une requête LINQ peut se terminer par 'group ... by ...', auquel cas le résultat est 'IGrouping', ce qui serait essentiellement équivalent à votre classe anonyme ici. –

+0

C'est vrai; En y réfléchissant, la raison principale pour laquelle j'ai utilisé cette méthode excessive est que la plupart des cas que j'utilise grouper par j'ai un autre agrégat, tel que LastLogin = result.Max (p => p.LastLogin). – JasonTrue

+0

Bien que vous y pensiez, l'utilisation du type anonyme signifie que vous n'appelez qu'une seule fois la méthode Count(); Si vous affichez toujours le nombre, vous n'avez pas besoin de cette petite efficacité, mais si vous décidez d'afficher le nombre ou non en fonction de sa valeur, comme ci-dessus, cela vous évitera une itération supplémentaire sur les éléments groupés . – JasonTrue

0

Essayez ceci: S'il vous plaît excuser la mauvaise syntaxe ... mon Asp.Net est rouillé, espérons que vous avez l'idée ...

<% 
    Dictionary<string,int> counts = new Dictionary<string, int>(); 
    foreach (User usedBy in discountDto.UsedBy) 
    { %> 
     <%if (counts.Contains(usedBy.FullName)) counts[usedBy.FullName]++; 
      else counts.Add(usedBy.FullName, 1);  
    } %> 
    <% foreach(string usdBy in counts) 
    { %> 
     <%=usdBy%><br /><% 
     <%if (counts[usdBy] > 1) 
     {%> 
      (<%=counts[usdBy];%>) <% 
     }%> 
    } %> 
+0

Vous avez oublié de générer le nombre dans la deuxième boucle. –

+0

En fait, la deuxième boucle ne sera même pas compilée, car vous aurez besoin d'un 'KeyValuePair ' pour la variable d'itération. –

+0

Non seulement la deuxième boucle n'utilise pas le bon type de données, mais elle tente également de générer une sortie à l'aide d'une variable inexistante. – Joshua

1

Quelque chose comme ça a fonctionné pour moi

foreach (var item in list.GroupBy(u => new {u.Surname, u.FirstName})) 
{ 
    %> 
    <%=Html.Encode(item.Key.FirstName)%> 
    <%=Html.Encode(item.Key.Surname)%> 
    <% 
    if (item.Count) > 1) 
    { 
     %> 
     (<%=item.Count%>) 
     <% 
    } 
}