通常我必须编写一个循环,该循环必须特殊情况下集合中的第一个项目,代码似乎永远不会像它应该的那样清晰。
如果不重新设计C#语言,那么编码这些循环的最佳方法是什么?
// this is more code to read then I would like for such a common concept
// and it is to easy to forget to update "firstItem"
foreach(x in yyy)
{
if (firstItem)
{
firstItem = false;
// other code when first item
}
// normal processing code
}
// this code is even harder to understand
if (yyy.Length > 0)
{
//Process first item;
For(int I = 1; I <yyy.Length; i++)
{
// process the other items.
}
}
答案 0 :(得分:13)
怎么样:
using (var erator = enumerable.GetEnumerator())
{
if (erator.MoveNext())
{
ProcessFirst(erator.Current);
//ProcessOther(erator.Current); // Include if appropriate.
while (erator.MoveNext())
ProcessOther(erator.Current);
}
}
如果您愿意,可以将其转换为扩展程序:
public static void Do<T>(this IEnumerable<T> source,
Action<T> firstItemAction,
Action<T> otherItemAction)
{
// null-checks omitted
using (var erator = source.GetEnumerator())
{
if (!erator.MoveNext())
return;
firstItemAction(erator.Current);
while (erator.MoveNext())
otherItemAction(erator.Current);
}
}
答案 1 :(得分:5)
我很想使用一些linq
using System.Linq;
var theCollectionImWorkingOn = ...
var firstItem = theCollectionImWorkingOn.First();
firstItem.DoSomeWork();
foreach(var item in theCollectionImWorkingOn.Skip(1))
{
item.DoSomeOtherWork();
}
答案 2 :(得分:5)
你可以尝试:
collection.first(x=>
{
//...
}).rest(x=>
{
//...
}).run();
第一个/休息看起来像:
FirstPart<T> first<T>(this IEnumerable<T> c, Action<T> a)
{
return new FirstPart<T>(c, a);
}
FirstRest rest<T>(this FirstPart<T> fp, Action<T> a)
{
return new FirstRest(fp.Collection, fp.Action, a);
}
您需要定义分类的FirstPart和FirstRest。 FirstRest需要像这样的run方法(Collection,FirstAction和RestAction属性):
void run()
{
bool first = true;
foreach (var x in Collection)
{
if (first) {
FirstAction(x);
first = false;
}
else {
RestAction(x);
}
}
}
答案 3 :(得分:4)
我一直使用first
变量方法,这对我来说似乎完全正常。
如果您更喜欢这样,可以使用LINQ First()
和Skip(1)
var firstItem = yyy.First();
// do the whatever on first item
foreach (var y in yyy.Skip(1))
{
// process the rest of the collection
}
答案 4 :(得分:2)
你写它的方式可能是最简洁的写法。毕竟,存在特定于第一个元素的逻辑,因此必须以某种方式表示。
答案 5 :(得分:2)
恕我直言最干净的方法是:尽量避免第一项的特殊情况。当然,这可能不适用于所有情况,但“特殊情况”可能表明您的程序逻辑比它需要的更复杂。
顺便说一句,我不会编码
if (yyy.Length > 0)
{
for(int i = 1; i <yyy.Length; i++)
{
// ...
}
}
但是
for(int i = 1; i <yyy.Length; i++)
{
// ...
}
(这本身就是一个如何避免不必要处理特殊情况的简单例子。)
答案 6 :(得分:1)
在这种情况下,我会像这样使用for循环:
for(int i = 0; i < yyy.Count; i++){
if(i == 0){
//special logic here
}
}
使用for循环还可以让你在其他情况下做一些特别的事情,比如最后一项,甚至是序列中的项目,等等。
答案 7 :(得分:1)
这是一个稍微简单的扩展方法来完成这项工作。这是KeithS's solution和my answer to a related Java question的组合:
public static void ForEach<T>(this IEnumerable<T> elements,
Action<T> firstElementAction,
Action<T> standardAction)
{
var currentAction = firstElementAction;
foreach(T element in elements)
{
currentAction(element);
currentAction = standardAction;
}
}
答案 8 :(得分:0)
这两种算法都是完全可以接受的处理第一个元素的算法,并且实际上并没有不同的方法。如果重复这种模式,你可以将它隐藏在ForEach()的重载之后:
public static void ForEach<T>(this IEnumerable<T> elements, Action<T> firstElementAction, Action<T> standardAction)
{
var firstItem = true;
foreach(T element in elements)
{
if(firstItem)
{
firstItem = false;
firstElementAction(element)
}
else
standardAction(element)
}
}
...
//usage
yyy.ForEach(t=>(other code when first item), t=>(normal processing code));
Linq让它更清洁一点:
PerformActionOnFirstElement(yyy.FirstOrDefault());
yyy.Skip(1).ForEach(x=>(normal processing code));
答案 9 :(得分:0)
虽然我不会亲自这样做,但还有另一种方法using enumerators,它减轻了条件逻辑的需要。像这样:
void Main()
{
var numbers = Enumerable.Range(1, 5);
IEnumerator num = numbers.GetEnumerator();
num.MoveNext();
ProcessFirstItem(num.Current); // First item
while(num.MoveNext()) // Iterate rest
{
Console.WriteLine(num.Current);
}
}
void ProcessFirstItem(object first)
{
Console.WriteLine("First is: " + first);
}
示例输出将是:
First is: 1
2
3
4
5
答案 10 :(得分:0)
我提出的另一个选择是
enum ItemType
{
First,
Last,
Normal
}
list.Foreach(T item, ItemType itemType) =>
{
if (itemType == ItemType.First)
{
}
// rest of code
};
编写扩展方法留给读者练习... 还应该使用两个布尔标志“IsFirst”和“IsLast”而不是ItemType枚举,或者ItemType是一个具有“IsFirst”和“IsLast”属性的对象吗?
答案 11 :(得分:0)
我的解决方案:
foreach (var x in yyy.Select((o, i) => new { Object = o, Index = i } )
{
if (x.Index == 0)
{
// First item logic
}
else
{
// Rest of items
}
}