C# 如何使用流畅的界面构建序列?
我正在尝试使用fluent界面构建一个集合,类似于以下(简化)示例: 我能想到的最佳解决方案是add():C# 如何使用流畅的界面构建序列?,c#,.net,algorithm,linq,fluent-interface,C#,.net,Algorithm,Linq,Fluent Interface,我正在尝试使用fluent界面构建一个集合,类似于以下(简化)示例: 我能想到的最佳解决方案是add(): IEnumerable添加(此IEnumerable coll,T项) { foreach(var t in coll)收益率t; 收益回报项目; } 这似乎增加了很多开销,每次调用都会重复这些开销 有更好的办法吗 更新: 在匆忙中,我过度简化了示例,并遗漏了一个重要的需求。现有coll中的最后一项影响下一项。因此,一个稍微简化的示例: var a = StartWith(1).A
IEnumerable添加(此IEnumerable coll,T项)
{
foreach(var t in coll)收益率t;
收益回报项目;
}
这似乎增加了很多开销,每次调用都会重复这些开销
有更好的办法吗
更新:
在匆忙中,我过度简化了示例,并遗漏了一个重要的需求。现有coll中的最后一项影响下一项。因此,一个稍微简化的示例:
var a = StartWith(1).Add(2).Add(3).Add(4).ToArray();
/* a = int[] {1,2,3,4}; */
var a = StartWith(1).Times10Plus(2).Times10Plus(3).Times10Plus(4).ToArray();
/* a = int[] {1,12,123,1234}; */
public static IEnumerable<T> StartWith<T>(T x)
{
yield return x;
}
static public IEnumerable<int> Times10Plus(this IEnumerable<int> coll, int item)
{
int last = 0;
foreach (var t in coll)
{
last = t;
yield return t;
}
yield return last * 10 + item;
}
var a=StartWith(1).Times10Plus(2).Times10Plus(3).Times10Plus(4).ToArray();
/*a=int[]{1,121231234}*/
公共静态IEnumerable StartWith(TX)
{
收益率x;
}
静态公共IEnumerable Times10Plus(此IEnumerable coll,int项)
{
int last=0;
foreach(coll中的变量t)
{
last=t;
收益率t;
}
收益率返回最后一个*10+项目;
}
您可以执行以下操作:
public static class MySequenceExtensions
{
public static IReadOnlyList<int> Times10Plus(
this IReadOnlyList<int> sequence,
int value) => Add(sequence,
value,
v => sequence[sequence.Count - 1] * 10 + v);
public static IReadOnlyList<T> Starts<T>(this T first)
=> new MySequence<T>(first);
public static IReadOnlyList<T> Add<T>(
this IReadOnlyList<T> sequence,
T item,
Func<T, T> func)
{
var mySequence = sequence as MySequence<T> ??
new MySequence<T>(sequence);
return mySequence.AddItem(item, func);
}
private class MySequence<T>: IReadOnlyList<T>
{
private readonly List<T> innerList;
public MySequence(T item)
{
innerList = new List<T>();
innerList.Add(item);
}
public MySequence(IEnumerable<T> items)
{
innerList = new List<T>(items);
}
public T this[int index] => innerList[index];
public int Count => innerList.Count;
public MySequence<T> AddItem(T item, Func<T, T> func)
{
Debug.Assert(innerList.Count > 0);
innerList.Add(func(item));
return this;
}
public IEnumerator<T> GetEnumerator() => innerList.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}
var a = 1.Starts().Times10Plus(2).Times10Plus(3).Times10Plus(4).ToArray();
产生预期结果({1,12,123,1234}
),我认为性能合理。您可以这样做:
public interface ISequence
{
ISequenceOp StartWith(int i);
}
public interface ISequenceOp
{
ISequenceOp Times10Plus(int i);
int[] ToArray();
}
public class Sequence : ISequence
{
public ISequenceOp StartWith(int i)
{
return new SequenceOp(i);
}
}
public class SequenceOp : ISequenceOp
{
public List<int> Sequence { get; set; }
public SequenceOp(int startValue)
{
Sequence = new List<int> { startValue };
}
public ISequenceOp Times10Plus(int i)
{
Sequence.Add(Sequence.Last() * 10 + i);
return this;
}
public int[] ToArray()
{
return Sequence.ToArray();
}
}
这次聚会有点晚了,但这里有一些想法 首先,考虑更一般的问题:
public static IEnumerable<A> AggregateSequence<S, A>(
this IEnumerable<S> items,
A initial,
Func<A, R, A> f)
{
A accumulator = initial;
yield return accumulator;
foreach(S item in items)
{
accumulator = f(accumulator, item);
yield return accumulator;
}
}
修改IDeque
和Deque
以明显的方式实现IEnumerable
,然后免费获得ToArray
。或者将其作为扩展方法:
static IEnumerable<T> EnumerateFromLeft(this IDeque<T> d)
{
var c = d;
while (!c.IsEmpty)
{
yield return c.PeekLeft();
c = c.DequeueLeft();
}
}
static IEnumerable Enumerated fromLeft(此标识为d)
{
var c=d;
而(!c.IsEmpty)
{
收益率返回c.peek left();
c=c.DequeueLeft();
}
}
有趣的问题。然而,我不确定有没有更好的方法来流利地完成这项工作。您可以让Add
方法采用params
数组,一次添加所有参数,但这并不能真正回答问题。我认为没有。除非您保留一些内部缓冲,例如使用ImmutableList
或类似的方法。现在所有这些方法调用都只是将相同的引用返回到单个可变(和变异)数据结构。所以如果你写var start=start(1);var nextValue=start.Times10Plus(2);控制台写入线(开始计数)代码>它将打印2,而不是1,这是错误的。@servy是的,我知道,但从问题中不清楚这是否是不需要的。无论如何,这很容易修复,只需使用不可变队列作为内部类型即可。如果枚举不是性能关键的,您甚至可以使用一个简单、直接的、按相反顺序枚举的不可变堆栈。换句话说,您现在又开始使用OP的解决方案了。@servy no,在添加具有不可变堆栈的新元素时,访问最后一个元素实际上要快得多。一点也不一样。
public static IEnumerable<A> AggregateSequence<S, A>(
this IEnumerable<S> items,
A initial,
Func<A, R, A> f)
{
A accumulator = initial;
yield return accumulator;
foreach(S item in items)
{
accumulator = f(accumulator, item);
yield return accumulator;
}
}
static IDeque<T> StartWith<T>(T t) => Deque<T>.Empty.EnqueueRight(t);
static IDeque<T> Op<T>(this IDeque<T> d, Func<T, T> f) => d.EnqueueRight(f(d.PeekRight()));
static IDeque<int> Times10Plus(this IDeque<int> d, int j) => d.Op(i => i * 10 + j);
static IEnumerable<T> EnumerateFromLeft(this IDeque<T> d)
{
var c = d;
while (!c.IsEmpty)
{
yield return c.PeekLeft();
c = c.DequeueLeft();
}
}