当我回答这个问题时 - An algorithm for a number divisible to n - 我提出了一个解决方案,可以生成所有正数长数的有序数,只使用数字0
& 9
。
但是我对我提出的两个选项真的不满意。第一个不是懒惰的,基本上是在返回第一个值之前生成的。
第二个更接近标记,但逻辑相当复杂,包含许多“神奇”数字
我很想知道是否有人可以为我提出快速懒惰的解决方案,最好使用签名Func<IEnumerable<long>> generate = ...;
或其他IEnumerable<long> Generate() { ... }
。
我的第一个选择是:
Func<IEnumerable<long>> generateA = () =>
{
Func<long, IEnumerable<long>> extend =
x => new [] { x * 10, x * 10 + 9 };
Func<long, IEnumerable<long>> generate2 = null;
generate2 = x =>
x <= 0L
? Enumerable.Empty<long>()
: new [] { x }
.Concat(
extend(x)
.SelectMany(y => generate2(y)))
.OrderBy(z => z);
return generate2(9L);
};
第二个是:
Func<IEnumerable<long>> generateB = () =>
{
var powers =
Enumerable
.Range(0, 18)
.Aggregate(
new List<long>() { 1L },
(a, _) => { a.Add(a.Last() * 10); return a; })
.ToArray();
return Enumerable
.Range(1, 393215) //largest expressable value using `0` & `9` only.
.Select(i => new BitArray(new [] { i })
.Cast<bool>()
.Take(19) //largest expressable value using `0` & `9` only.
.Select((x, n2) => (x ? 9L : 0L) * powers[n2])
.Sum());
};
两种方法都返回393,215个值,以9
开头,以9,099,999,999,999,999,999
结尾。
任何想要使方法变得懒惰和简单的想法?
答案 0 :(得分:3)
我认为使用yield return
编写可理解的,懒惰的方法更容易,这在Lambdas中是不可用的。尝试仅使用LINQ执行此操作会让人更难理解。
public class Program
{
public static void Main(string[] args)
{
var items = Generate();
var first = items.Take(8);
var count = items.Count();
var last = items.Skip(count - 4);
Console.WriteLine("First items: {0}", string.Join(", ", first));
Console.WriteLine("Last items: {0}", string.Join(", ", last));
Console.WriteLine("Count: {0}", count);
}
private static IEnumerable<long> Generate()
{
return GenerateAll().TakeWhile(i => i >= 0);
}
// generates an infinite sequence using GenerateNext
private static IEnumerable<long> GenerateAll()
{
IEnumerable<long> items = new[] { 9L };
while(true)
{
foreach(var item in items)
{
yield return item;
}
items = GenerateNext(items);
}
}
// generates the next items in the sequence.
private static IEnumerable<long> GenerateNext(IEnumerable<long> xs)
{
foreach(var x in xs)
{
long x2 = 10 * x;
yield return x2;
yield return x2 + 9;
}
}
}
输出:
第一项:9,90,99,900,909,990,999,9000
最后项目:9099999999999999900,9099999999999999909,9099999999999999990,9099999999999999999
数:393215
答案 1 :(得分:0)
仅仅为了记录,我的最终答案受到了“Mike Z”的启发 - 我将给出答案 - 它是:
Func<IEnumerable<long>> generate = () =>
{
Func<long, IEnumerable<long>> extend =
x => new [] { x * 10, x * 10 + 9 };
Func<IEnumerable<long>, IEnumerable<long>> generate2 = null;
generate2 = ns =>
{
var clean = ns.Where(n => n > 0).ToArray();
return clean.Any()
? clean.Concat(generate2(clean.SelectMany(extend)))
: Enumerable.Empty<long>();
};
return generate2(new[] { 9L, });
};
事实证明这是懒惰的,而且非常快。