我经常发现自己在foreach循环中执行以下索引计数器混乱,以查明我是否在第一个元素。是否有更优雅的方式在 C#中执行此操作,类似于if(this.foreach.Pass == 1)
等。
int index = 0;
foreach (var websitePage in websitePages) {
if(index == 0)
classAttributePart = " class=\"first\"";
sb.AppendLine(String.Format("<li" + classAttributePart + ">" +
"<a href=\"{0}\">{1}</a></li>",
websitePage.GetFileName(), websitePage.Title));
index++;
}
答案 0 :(得分:13)
另一种方法是接受“丑陋的部分”必须在某处实现并提供隐藏“丑陋部分”的抽象,这样你就不必在多个地方重复它并且可以专注于特定的算法。这可以使用C#lambda表达式完成(或者如果你只限于.NET 2.0,则使用C#2.0匿名委托):
void ForEachWithFirst<T>(IEnumerable<T> en,
Action<T> firstRun, Action<T> nextRun) {
bool first = true;
foreach(var e in en) {
if (first) { first = false; firstRun(e); } else nextRun(e);
}
}
现在您可以使用此可重用方法来实现您的算法:
ForEachWithFirst(websitePages,
(wp => sb.AppendLine(String.Format("<li class=\"first\">" +
"<a href=\"{0}\">{1}</a></li>", wp.GetFileName(), wp.Title)))
(wp => sb.AppendLine(String.Format("<li>" +
"<a href=\"{0}\">{1}</a></li>", wp.GetFileName(), wp.Title))) );
您可以根据确切的重复模式设计不同的抽象。好处是 - 由于lambda表达式 - 抽象的结构完全取决于你。
答案 1 :(得分:11)
稍微不那么冗长:
string classAttributePart = " class=\"first\"";
foreach (var websitePage in websitePages)
{
sb.AppendLine(String.Format("<li" + classAttributePart + "><a href=\"{0}\">{1}</a></li>", websitePage.GetFileName(), websitePage.Title));
classAttributePart = string.Empty;
}
如果您使用的是.NET 3.5,则可以使用Select的重载来为您提供索引和测试。那么你也不需要StringBuilder。这是代码:
string[] s = websitePages.Select((websitePage, i) =>
String.Format("<li{0}><a href=\"{1}\">{2}</a></li>\n",
i == 0 ? " class=\"first\"" : "",
websitePage.GetFileName(),
websitePage.Title)).ToArray();
string result = string.Join("", s);
它看起来有点冗长,但这主要是因为我打破了许多较短的长线。
答案 2 :(得分:4)
if (websitePages.IndexOf(websitePage) == 0)
classAttributePart = " class=\"last\"";
这可能更优雅,但它可能性能较差,因为它必须检查每个元素的索引。
答案 3 :(得分:4)
这可能略微更好
bool doInit = true;
foreach (var websitePage in websitePages)
{
if (doInit)
{
classAttributePart = " class=\"first\"";
doInit = false;
}
sb.AppendLine(String.Format("<li" + classAttributePart + "><a href=\"{0}\">{1}</a></li>", websitePage.GetFileName(), websitePage.Title));
}
我最终也做了很多这样的事情,也让我感到烦恼。
答案 4 :(得分:4)
您可以使用for
循环而不是foreach
循环。在这种情况下,你的for循环可以将它的索引从1开始,如果长度大于0,你可以在循环之外做第一个元素。
至少在这种情况下,你不会在每次迭代时进行额外的比较。
答案 5 :(得分:3)
另一种方法是使用jQuery's first selector来设置类而不是服务器端代码。
$(document).ready(function(){
$("#yourListId li:first").addClass("first");
}
答案 6 :(得分:2)
如果你只为第一个索引做这个,你可以在foreach循环之前完成。
答案 7 :(得分:2)
如果您只对第一个元素感兴趣,那么最好(最可读)的方法是使用LINQ来找出第一个元素。像这样:
var first = collection.First();
// do something with first element
....
foreach(var item in collection){
// do whatever you need with every element
....
if(item==first){
// and you can still do special processing here provided there are no duplicates
}
}
如果您需要索引的数值或非第一索引,您可以随时
foreach (var pair in collection.Select((item,index)=>new{item,index}))
{
// do whatever you need with every element
....
if (pair.index == 5)
{
// special processing for 5-th element. If you need to do this, your design is bad bad bad
}
}
PS最好的方法是使用for
- 循环。仅在foreach
不可用时使用for
(即集合为IEnumerable
而不是列表或其他内容)
答案 8 :(得分:1)
这个怎么样?
var iter = websitePages.GetEnumerator();
iter.MoveNext();
//Do stuff with the first element
do {
var websitePage = iter.Current;
//For each element (including the first)...
} while (iter.MoveNext());
答案 9 :(得分:0)
正如我父亲所说,“使用合适的工具来完成工作”。
在这种情况下,看看你的循环需要做什么。
否则,为了回答你的问题,似乎没有一种简单的非冗长的方法来识别列表项的索引,因为它是在foreach循环中访问的。
答案 10 :(得分:0)
public static class ExtenstionMethods
{
public static IEnumerable<KeyValuePair<Int32, T>> Indexed<T>(this IEnumerable<T> collection)
{
Int32 index = 0;
foreach (var value in collection)
{
yield return new KeyValuePair<Int32, T>(index, value);
++index;
}
}
}
foreach (var iter in websitePages.Indexed())
{
var websitePage = iter.Value;
if(iter.Key == 0) classAttributePart = " class=\"first\"";
sb.AppendLine(String.Format("<li" + classAttributePart + "><a href=\"{0}\">{1}</a></li>", websitePage.GetFileName(), websitePage.Title));
}
答案 11 :(得分:0)
在这个例子中,你可以通过这种方式去掉索引。
foreach (var websitePage in websitePages)
{
classAttributePart = classAttributePart ?? " class=\"first\"";
sb.AppendLine(String.Format("<li" + classAttributePart + "><a href=\"{0}\">{1}</a></li>", websitePage.GetFileName(), websitePage.Title));
}
最好检查结果数据变量以执行此类任务。 在这种情况下,它检查classAttributePart字符串的null并附加初始值。