diff --git a/lib/underscore.lua b/lib/underscore.lua index 7415190..5040bfd 100644 --- a/lib/underscore.lua +++ b/lib/underscore.lua @@ -82,6 +82,58 @@ end -- iter +function Underscore.funcs.gzip(left_iter, right_iter) + local left_iter_is_function = type(left_iter) == "function" + local right_iter_is_function = type(right_iter) == "function" + + if left_iter_is_function and right_iter_is_function then + return coroutine.wrap(function() + local left_item, right_item = left_iter(), right_iter() + while left_item ~= nil and right_item ~= nil do + coroutine.yield(left_item, right_iter) + left_item, right_item = left_iter(), right_iter() + end + end) + elseif left_iter_is_function then + return coroutine.wrap(function() + local i = 1 + local left_item , right_item, i = left_iter(), right_iter[i], i + 1 + while left_item ~= nil and right_item ~= nil do + coroutine.yield(left_item, right_item) + left_item , right_item, i = left_iter(), right_iter[i], i + 1 + end + end) + elseif right_iter_is_function then + return coroutine.wrap(function() + local i = 1 + local left_item , right_item, i = left_iter[i], right_iter(), i + 1 + while left_item ~= nil and right_item ~= nil do + coroutine.yield(left_item, right_item) + left_item , right_item, i = left_iter[i], right_iter(), i + 1 + end + end) + else + return coroutine.wrap(function() + local i = 1 + local left_item, right_item, i = left_iter[i], right_iter[i], i + 1 + while left_item ~= nil and right_item ~= nil do + coroutine.yield(left_item, right_item) + left_item, right_item, i = left_iter[i], right_iter[i], i + 1 + end + end) + end +end + +function Underscore.funcs.zip(left_iter, right_iter) + local zipped = {} + local i = 1 + for left_item, right_item in Underscore.funcs.gzip(left_iter, right_iter) do + zipped[i] = {left_item, right_item} + i = i + 1 + end + return zipped +end + function Underscore.funcs.each(list, func) for i in Underscore.iter(list) do func(i) diff --git a/spec/spec_helper.lua b/spec/spec_helper.lua index 206bba3..da189e7 100644 --- a/spec/spec_helper.lua +++ b/spec/spec_helper.lua @@ -1,5 +1,7 @@ require 'luaspec' require 'luamock' + +package.path = "../lib/?.lua;" .. package.path _ = require 'underscore' function matchers.should_equal(value, expected) diff --git a/spec/zip_spec.lua b/spec/zip_spec.lua new file mode 100644 index 0000000..a0cff86 --- /dev/null +++ b/spec/zip_spec.lua @@ -0,0 +1,205 @@ +require 'spec_helper' + +describe["_.zip"] = function() + describe["*** when providing two lists ***"] = function() + describe["when both lists are of equal length"] = function() + before = function() + left_list = {1, 3, 5} + right_list = {2, 4, 6} + result = _.zip(left_list, right_list) + end + + it["should return {{1,2}, {3,4}, {5,6}}"] = function() + expect( + result[1][1] == 1 and + result[1][2] == 2 and + result[2][1] == 3 and + result[2][2] == 4 and + result[3][1] == 5 and + result[3][2] == 6 + ).should_be(true) + end + end + + describe["when the left list is shorter than the right"] = function() + before = function() + left_list = {1, 3, 5} + right_list = {2, 4, 6, 7} + result = _.zip(left_list, right_list) + end + + it["\tshould return {{1,2}, {3,4}, {5,6}}"] = function() + expect( + result[1][1] == 1 and + result[1][2] == 2 and + result[2][1] == 3 and + result[2][2] == 4 and + result[3][1] == 5 and + result[3][2] == 6 + ).should_be(true) + end + end + + describe["when the left list is longer than the right"] = function() + before = function() + left_list = {1, 3, 5, 7} + right_list = {2, 4, 6} + result = _.zip(left_list, right_list) + end + + it["should return {{1,2}, {3,4}, {5,6}}"] = function() + expect( + result[1][1] == 1 and + result[1][2] == 2 and + result[2][1] == 3 and + result[2][2] == 4 and + result[3][1] == 5 and + result[3][2] == 6 + ).should_be(true) + end + end + end + + describe["*** when left is function, right a list ***"] = function() + describe["when the left function will yield the SAME number of values as the right list"] = function() + before = function() + left_func = coroutine.wrap(function() + for i=1, 5, 2 do + coroutine.yield(i) + end + end) + right_list = {2, 4, 6} + result = _.zip(left_func, right_list) + end + + it["should return {{1,2}, {3,4}, {5,6}}"] = function() + expect( + result[1][1] == 1 and + result[1][2] == 2 and + result[2][1] == 3 and + result[2][2] == 4 and + result[3][1] == 5 and + result[3][2] == 6 + ).should_be(true) + end + end + + describe["when the left function will yield LESS values as the right list"] = function() + before = function() + left_func = coroutine.wrap(function() + for i=1, 5, 2 do + coroutine.yield(i) + end + end) + right_list = {2, 4, 6, 7} + result = _.zip(left_func, right_list) + end + + it["should return {{1,2}, {3,4}, {5,6}}"] = function() + expect( + result[1][1] == 1 and + result[1][2] == 2 and + result[2][1] == 3 and + result[2][2] == 4 and + result[3][1] == 5 and + result[3][2] == 6 + ).should_be(true) + end + end + + describe["when the left function will yield MORE values as the right list"] = function() + before = function() + left_func = coroutine.wrap(function() + for i=1, 7, 2 do + coroutine.yield(i) + end + end) + right_list = {2, 4, 6} + result = _.zip(left_func, right_list) + end + + it["should return {{1,2}, {3,4}, {5,6}}"] = function() + expect( + result[1][1] == 1 and + result[1][2] == 2 and + result[2][1] == 3 and + result[2][2] == 4 and + result[3][1] == 5 and + result[3][2] == 6 + ).should_be(true) + end + end + end + + describe["*** when right is function, left a list ***"] = function() + describe["when the right function will yield the same number of values as the left list"] = function() + before = function() + local left_list = {1, 3, 5} + local right_func = coroutine.wrap(function() + for i=2, 6, 2 do + coroutine.yield(i) + end + end) + result = _.zip(left_list, right_func) + end + + it["should return {{1,2}, {3,4}, {5,6}}"] = function() + expect( + result[1][1] == 1 and + result[1][2] == 2 and + result[2][1] == 3 and + result[2][2] == 4 and + result[3][1] == 5 and + result[3][2] == 6 + ).should_be(true) + end + end + + describe["when the right function will yield LESS values as the left list"] = function() + before = function() + local left_list = {1, 3, 5} + local right_func = coroutine.wrap(function() + for i=2, 4, 2 do + coroutine.yield(i) + end + end) + result = _.zip(left_list, right_func) + end + + it["should return {{1,2}, {3,4}}"] = function() + expect( + result[1][1] == 1 and + result[1][2] == 2 and + result[2][1] == 3 and + result[2][2] == 4 + ).should_be(true) + end + end + + describe["when the right function will yield MORE values as the left list"] = function() + before = function() + local left_list = {1, 3, 5} + local right_func = coroutine.wrap(function() + for i=2,8,2 do + coroutine.yield(i) + end + end) + result = _.zip(left_list, right_func) + end + + it["should return {{1,2}, {3,4}, {5,6}}"] = function() + expect( + result[1][1] == 1 and + result[1][2] == 2 and + result[2][1] == 3 and + result[2][2] == 4 and + result[3][1] == 5 and + result[3][2] == 6 + ).should_be(true) + end + end + end +end + + +spec:report(true)