【问题标题】:how to loop over generic List<T> and group per 3 items如何遍历通用 List<T> 并按 3 项分组
【发布时间】:2012-07-24 07:17:51
【问题描述】:

我想遍历 MemberProfiles 的通用列表:

List<MemberProfile> jobseekers    

,并将项目分组到 &lt;div class='group'&gt;tag 中。每个&lt;div class="group"&gt; 应该包含 3 个这样的求职者:

<div class="group">
    <div class="jobseeker">
        ...data jobseeker
    </div>
</div>

我在通用列表上尝试了不同的方法,例如 .skip() 和 .take(),但我没有成功实现这个场景。

我的代码如下所示:

foreach (MemberProfile jobseekerProfile in Jobseekers)
{
    if (jobseekerProfile != null)
    {
        Label lblJobseeker = new Label();
        StringBuilder sbJobseeker = new StringBuilder();
        sbJobseeker.Append(string.Format("<p><strong>{0}&nbsp;{1}</strong><br />", jobseekerProfile.FirstName, jobseekerProfile.LastName));
        XPathNodeIterator preValues = library.GetPreValues(1362);
        preValues.MoveNext();
        XPathNodeIterator iterator2 = preValues.Current.SelectChildren("preValue", "");
        while (iterator2.MoveNext())
        {
            if (jobseekerProfile.JobType == iterator2.Current.GetAttribute("id", ""))
            {
                sbJobseeker.Append(string.Format("looking for a {0}<br />", iterator2.Current.Value));
            }
        }
        XPathNodeIterator iterator3 = library.GetPreValues(1363);
        iterator3.MoveNext();
        XPathNodeIterator iterator4 = iterator3.Current.SelectChildren("preValue", "");
        StringBuilder sbJobExperience = new StringBuilder();
        string[] strJobExperience = jobseekerProfile.JobExperience.Split(new char[] { ',' });
        int counter = 1;
        while (iterator4.MoveNext())
        {
            if (jobseekerProfile.JobExperience.Contains(iterator4.Current.GetAttribute("id", "")))
            {
                if (counter != strJobExperience.Count<string>())
                {
                    sbJobExperience.Append(string.Format("{0}, ", iterator4.Current.Value));
                    counter++;
                }
                else
                {
                    sbJobExperience.Append(string.Format("{0}", iterator4.Current.Value));
                }
            }
        }
        sbJobseeker.Append(string.Format("Fields of experience: {0}<br />", sbJobExperience.ToString()));
        sbJobseeker.Append(string.Format("Years of experience: {0}<br />", jobseekerProfile.YearsExperience));
        sbJobseeker.Append(string.Format("Country: {0}<br />", jobseekerProfile.Country));
        sbJobseeker.Append(string.Format("<form name='frmSelect' action='/selectjobcandidate.aspx' method='post'><input type='hidden' name='username' value='{0}' /><input type='submit' value='select candidate' /></form>", jobseekerProfile.UserName));
        lblJobseeker.Text = sbJobseeker.ToString();
        phListJobseekers.Controls.Add(lblJobseeker);
    }
}    

有人可以让我走上正确的轨道来实现这个场景吗?

【问题讨论】:

  • 你能发布你的代码吗?
  • 组是 MemberProfile 的一个属性还是这些列表是如何相关的?
  • 您可以在 foreach 循环中使用“计数器”,但如果您发布代码会更有帮助
  • 嗨,蒂姆,不,该组不是 MemberProfile 的属性,我只是尝试通过循环逻辑循环遍历列表中的所有求职者,并在
    标签
  • 使用for 循环而不是foreach 循环应该更明智

标签: c# asp.net generics


【解决方案1】:
for (var i = 0; i < Jobseekers.Count; i += 3)
{
    foreach (MemberProfile jobseekerProfile in Jobseekers.Skip(i).Take(3))
    {

    }
}

这就是你所追求的吗?

【讨论】:

  • 嗨 MortenRogenes,是的,这看起来是一个非常优雅的循环结构。我会试一试,如果成功了,现在就让你试试。
  • 我认为这是最好的解决方案,因为它在读取代码时非常清楚。
  • 取决于编译器是否能够避免在每次循环迭代时执行“Skip”操作,这也可能是所有建议的解决方案中最慢的(如果 Skip 必须再次遍历整个 IEnumerable 并且再次)。
  • @Timbo 编译器不会对此进行优化以应用 Skip 一次。 Skip 和 Take 只是扩展方法,(我相信,虽然我不是 C# 编译器开发人员)没有来自编译器的特殊情况。所以这个二次算法。
  • 嗨 MortenRogenes,我实现了你的循环,但结果不是我所希望的。现在
    元素是嵌套的
    元素。我的列表 包含 6 个求职者。但是页面上呈现了 21 个重复的求职者。
【解决方案2】:

既然你似乎想用 linq 来做,我们开始吧:

var tagged = Jobseekers.Select((x, i) => new { x, i });
var grouped = tagged.ToLookup(t => (t.i - 1) / 3, t => t.x);

foreach (var group in grouped)
{
    Console.WriteLine("Group:");
    foreach (var item in group)
    {
        Console.WriteLine(item);
    }
}

【讨论】:

  • 嗨 Timbo,感谢您的代码。我尝试实现它,但出现了几个构建错误:错误 1 ​​运算符“-”不能应用于“UmbracoRegistration.MemberProfile”和“int”类型的操作数 C:\repos\umbracoregistration\UmbracoRegistration\UmbracoRegistration\Usercontrols\ListJobseekers.ascx .cs 32 63 UmbracoRegistration 错误 2 无法将 lambda 表达式转换为类型“System.Collections.Generic.IEqualityComparer”,因为它不是委托类型
  • @Toontje 我的错,必须在第一行交换 x 和 i。这就是使用整数列表进行测试时发生的情况:(
  • 嗨 Timbo,我交换了 x 和 i,但仍然出现编译器错误:错误 2 运算符“-”不能应用于“umbraco.cms.businesslogic.web.Document”类型的操作数和'int' 我的列表项是 Document 类型(Umbraco 对象)
【解决方案3】:

来自以下答案:Split List into Sublists with LINQ

public static List<List<MemberProfile>> Split(List<MemberProfile> source)
{
    return  source
        .Select((x, i) => new { Index = i, Value = x })
        .GroupBy(x => x.Index / 3)
        .Select(x => x.Select(v => v.Value).ToList())
        .ToList();
}

也可以查看其他答案

【讨论】:

  • 好的,我将尝试 sublist LINQ 示例。我猜“来源”是我的通用 List 求职者列表?
【解决方案4】:

您的问题并不完全清楚,但您似乎想将您的 jobseekers 列表拆分为每组 3 个元素,然后对每组 3 个元素执行一些操作以获得一些 HTML sn-p,所以输出是一个 HTML sn-ps 序列。

假设jobseekers 总是有3 个元素的倍数。如果它并不总是有 3 个元素,则此解决方案将保留最后一组元素,并且您可以通过删除任何少于 3 个元素的组来过滤掉该组(Where 将紧随GroupBy)。使用 LINQ:

IEnumerable<string> htmlSnippets = jobseekers
    .Zip(Enumerable.Range(0, jobseekers.Count), Tuple.Create)
    .GroupBy(tup => tup.Item2 / 3)
    .Select(GenerateHtmlString);
string combinedHtmlString = string.Join(string.Empty, htmlSnippets);

public string GenerateHtmlString(IEnumerable<MemberProfile> profiles)
{
    return string.Format(@"<div class=""jobseeker"">{0}</div>",
        // The question doesn't specify how the 3 jobseekers are rendered in HTML
        );
}

【讨论】:

    猜你喜欢
    相关资源
    最近更新 更多
    热门标签