【问题标题】:Lazily generating ordered enumerable of all positive longs that only use the numerals `0` & `9`懒惰地生成仅使用数字“0”和“9”的所有正长的有序枚举
【发布时间】:2014-03-02 01:30:00
【问题描述】:

当我回答这个问题时 - An algorithm for a number divisible to n - 我提出了一个解决方案,该解决方案将生成所有正长整数的有序枚举,这些正整数仅使用数字 09

但是,我对我提出的两个选项真的不满意。第一个不是懒惰的,基本上是在返回第一个值之前生成的。

第二个更接近目标,但逻辑相当复杂,包含很多“神奇”数字

我很想看看是否有人可以为我提出一个快速延迟生成的解决方案,最好使用签名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 结尾的值。

有什么想法可以制作一种既懒惰又简单的方法?

【问题讨论】:

    标签: c# linq lambda ienumerable generator


    【解决方案1】:

    我认为使用 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

    【讨论】:

      【解决方案2】:

      为了记录,我的最终答案受到了“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, });
      };
      

      事实证明这是懒惰的,有序的,而且非常快。

      【讨论】:

        猜你喜欢
        • 2019-02-25
        • 2018-04-28
        • 2011-12-31
        • 1970-01-01
        • 2011-03-24
        • 2010-09-26
        • 1970-01-01
        • 1970-01-01
        • 2020-04-01
        相关资源
        最近更新 更多