Advertisement
funny_falcon

Delayed list in Ruby

Feb 13th, 2013
177
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 5.11 KB | None | 0 0
  1. class DCons
  2.   include Enumerable
  3.  
  4.   UNDEF = Object.new.freeze
  5.  
  6.   class NILC
  7.     include Enumerable
  8.  
  9.     def first(n = UNDEF)
  10.       n.equal?(UNDEF) ? nil : self
  11.     end
  12.  
  13.     def tail
  14.       self
  15.     end
  16.  
  17.     def drop(n)
  18.       self
  19.     end
  20.  
  21.     def nil?
  22.       true
  23.     end
  24.  
  25.     def each
  26.     end
  27.  
  28.     def _try
  29.       self
  30.     end
  31.  
  32.     def empty?
  33.       true
  34.     end
  35.   end
  36.   NIL = NILC.new
  37.  
  38.   def initialize(first, tail = UNDEF, &calc)
  39.     @first = first
  40.     @tail = tail
  41.     @calc = calc  if @tail.equal? UNDEF
  42.   end
  43.  
  44.   def empty?
  45.     false
  46.   end
  47.  
  48.   def first(n = UNDEF)
  49.     if n.equal?(UNDEF)
  50.       @first
  51.     else
  52.       res = []
  53.       list = self
  54.       until list.nil? || n <= 0
  55.         res << list.first
  56.         list = list.tail
  57.         n -= 1
  58.       end
  59.       res
  60.     end
  61.   end
  62.  
  63.   def take(n)
  64.     first(n)
  65.   end
  66.  
  67.   def tail
  68.     if @tail.equal? UNDEF
  69.       calc, @calc = @calc, nil
  70.       @tail = calc ? calc.call : NIL
  71.     else
  72.       @tail
  73.     end
  74.   end
  75.  
  76.   def drop(n)
  77.     list = self
  78.     until list.nil? || n <= 0
  79.       list = list.tail
  80.       n -= 1
  81.     end
  82.     list
  83.   end
  84.  
  85.   def each
  86.     if block_given?
  87.       list = self
  88.       until list.nil?
  89.         yield list.first
  90.         list = list.tail
  91.       end
  92.     end
  93.     self
  94.   end
  95.  
  96.   def _try
  97.     tail.nil? ? NIL : yield
  98.   end
  99.  
  100.   def find_all(&filter)
  101.     list = self
  102.     list = list.tail  until filter.call(list.first)
  103.     dcons(list.first){ list._try{ list.tail.find_all(&filter) } }
  104.   end
  105.  
  106.   alias select find_all
  107.  
  108.   def map(&calc)
  109.     dcons calc.call(first) do
  110.       _try{ tail.map(&calc) }
  111.     end
  112.   end
  113.   alias collect map
  114.  
  115.   def zip(*args)
  116.     cars = args.map{|o| o.first}
  117.     zipped = dcons [first, *cars] do
  118.       _try {
  119.         cdrs = args.map{|o| o.tail}
  120.         tail.zip(*cdrs)
  121.       }
  122.     end
  123.     if block_given?
  124.       zipped.each Proc.new
  125.       nil
  126.     else
  127.       zipped
  128.     end
  129.   end
  130.  
  131.   def zip_map(*args, &calc)
  132.     zip(*args).map(&calc)
  133.   end
  134.  
  135.   def _chunk_cons(cur_key, state, &block)
  136.     list = self
  137.     while true
  138.       case cur_key
  139.       when nil, :_separator
  140.         return NIL if (list = list.tail).nil?
  141.         cur_key = state ? yield(list.first, state) : yield(list.first)
  142.       when :_alone
  143.         return dcons([:_alone, [list.first]]){
  144.           list._try{ list.tail._chunk_cons(key, state, &block) }
  145.         }
  146.       else
  147.         break
  148.       end
  149.     end
  150.     key = cur_key
  151.     res = []
  152.     until list.nil? || key != cur_key
  153.       res << list.first
  154.       unless (list = list.tail).nil?
  155.         key = state ? yield(list.first, state) : yield(list.first)
  156.       else
  157.         return dcons([cur_key, res])
  158.       end
  159.     end
  160.     dcons([cur_key, res]){
  161.       list.nil? ? NIL : list._chunk_cons(key, state, &block)
  162.     }
  163.   end
  164.  
  165.   def chunk(initial_state = nil, &block)
  166.     state = initial_state.dup  if initial_state
  167.     _chunk_cons yield(first), state, &block
  168.   end
  169.  
  170.   def drop_while
  171.     list = self
  172.     list = list.tail  while !list.nil? && yield(list.first)
  173.     list
  174.   end
  175.  
  176.   def take_while(&block)
  177.     if yield(first)
  178.       dcons(first){ _try{ tail.take_while(&block) } }
  179.     else
  180.       NIL
  181.     end
  182.   end
  183.  
  184.   def each_cons(n)
  185.     if (v = take(n)).size < n
  186.       return block_given? ? nil : NIL
  187.     end
  188.     cons = dcons(v){ tail.each_cons(n) }
  189.     if block_given?
  190.       cons.each{|args| yield args}
  191.       nil
  192.     else
  193.       cons
  194.     end
  195.   end
  196.  
  197.   def each_slice(n)
  198.     cons = dcons(take(n)){
  199.       tl = drop(n)
  200.       tl.nil? ? NIL : tl.each_slice(n)
  201.     }
  202.     if block_given?
  203.       cons.each{|args| yield args}
  204.       nil
  205.     else
  206.       cons
  207.     end
  208.   end
  209. end
  210.  
  211. def dcons(first, *caars, &calc)
  212.   unless caars.empty?
  213.     DCons.new(first, dcons(*caars, &calc))
  214.   else
  215.     DCons.new(first, &calc)
  216.   end
  217. end
  218.  
  219. module Enumerable
  220.   def tail
  221.     puts "ENUM TAKE #{self.inspect}"
  222.     drop(1)
  223.   end
  224. end
  225.  
  226. class Array
  227.   def sum
  228.     p self
  229.     inject(0){|s, i| s + i}
  230.   end
  231. end
  232.  
  233. fib = dcons(0, 1){ fib.zip_map(fib.tail, &:sum) }
  234. p fib.take(ARGV[0].to_i)
  235. p fib.take(ARGV[0].to_i)
  236. fib2 = fib.tail.tail.tail
  237. fib = nil
  238. p fib2.take(4)
  239.  
  240. p fib2.find{|i| i > 1e10}
  241. p fib2.find_all(&:even?).take(10)
  242.  
  243. p fib2.chunk(&:even?).take(10)
  244.  
  245.  
  246. ints = dcons(0){ ints.map{|i| i+1} }
  247. p ints.take(10)
  248. p ints.zip((100..105)).take(10)
  249.  
  250.  
  251. p ints.chunk{|i| i % 3 == 2 ? nil : i / 3}.take(10)
  252. p ints.chunk{|i| i % 3 == 1 ? nil : i / 3}.take(10)
  253. p ints.chunk(""){|i| i % 3 == 1 ? nil : i / 3}.take(10)
  254.  
  255.  
  256. pure = ints.drop(2)
  257. pure = pure.find_all{|i|
  258.   sqrt = Math.sqrt(i)
  259.   pure.take_while{|j| j <= sqrt}.all?{|j| i % j != 0}
  260. }
  261. p pure.take_while{|i| i < 1000}.to_a
  262.  
  263.  
  264. def sieve(stream)
  265.   first = stream.first
  266.   dcons(first){
  267.     stream._try {
  268.       sieve stream.tail.find_all{|v| v % first != 0}
  269.     }
  270.   }
  271. end
  272. pure1 = sieve(ints.drop(2))
  273. p pure1.take_while{|i| i < 1000}.to_a
  274.  
  275. def timeit
  276.   t = Time.now
  277.   yield
  278.   Time.now - t
  279. end
  280. puts timeit{ pure.take_while{|i| i < 5000}.to_a }
  281. puts timeit{ pure1.take_while{|i| i < 5000}.to_a }
  282.  
  283.  
  284. p pure.take_while{|i| i < 20}.each_cons(3).to_a
  285. p pure.take_while{|i| i < 20}.each_slice(3).to_a
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement