fold.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. define("dojox/lang/functional/fold", ["dojo/_base/lang", "dojo/_base/array", "dojo/_base/window", "./lambda"],
  2. function(lang, arr, win, df){
  3. // This module adds high-level functions and related constructs:
  4. // - "fold" family of functions
  5. // Notes:
  6. // - missing high-level functions are provided with the compatible API:
  7. // foldl, foldl1, foldr, foldr1
  8. // - missing JS standard functions are provided with the compatible API:
  9. // reduce, reduceRight
  10. // - the fold's counterpart: unfold
  11. // Defined methods:
  12. // - take any valid lambda argument as the functional argument
  13. // - operate on dense arrays
  14. // - take a string as the array argument
  15. // - take an iterator objects as the array argument (only foldl, foldl1, and reduce)
  16. var empty = {};
  17. /*=====
  18. var df = dojox.lang.functional;
  19. =====*/
  20. lang.mixin(df, {
  21. // classic reduce-class functions
  22. foldl: function(/*Array|String|Object*/ a, /*Function*/ f, /*Object*/ z, /*Object?*/ o){
  23. // summary: repeatedly applies a binary function to an array from left
  24. // to right using a seed value as a starting point; returns the final
  25. // value.
  26. if(typeof a == "string"){ a = a.split(""); }
  27. o = o || win.global; f = df.lambda(f);
  28. var i, n;
  29. if(lang.isArray(a)){
  30. // array
  31. for(i = 0, n = a.length; i < n; z = f.call(o, z, a[i], i, a), ++i);
  32. }else if(typeof a.hasNext == "function" && typeof a.next == "function"){
  33. // iterator
  34. for(i = 0; a.hasNext(); z = f.call(o, z, a.next(), i++, a));
  35. }else{
  36. // object/dictionary
  37. for(i in a){
  38. if(!(i in empty)){
  39. z = f.call(o, z, a[i], i, a);
  40. }
  41. }
  42. }
  43. return z; // Object
  44. },
  45. foldl1: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){
  46. // summary: repeatedly applies a binary function to an array from left
  47. // to right; returns the final value.
  48. if(typeof a == "string"){ a = a.split(""); }
  49. o = o || win.global; f = df.lambda(f);
  50. var z, i, n;
  51. if(lang.isArray(a)){
  52. // array
  53. z = a[0];
  54. for(i = 1, n = a.length; i < n; z = f.call(o, z, a[i], i, a), ++i);
  55. }else if(typeof a.hasNext == "function" && typeof a.next == "function"){
  56. // iterator
  57. if(a.hasNext()){
  58. z = a.next();
  59. for(i = 1; a.hasNext(); z = f.call(o, z, a.next(), i++, a));
  60. }
  61. }else{
  62. // object/dictionary
  63. var first = true;
  64. for(i in a){
  65. if(!(i in empty)){
  66. if(first){
  67. z = a[i];
  68. first = false;
  69. }else{
  70. z = f.call(o, z, a[i], i, a);
  71. }
  72. }
  73. }
  74. }
  75. return z; // Object
  76. },
  77. foldr: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object*/ z, /*Object?*/ o){
  78. // summary: repeatedly applies a binary function to an array from right
  79. // to left using a seed value as a starting point; returns the final
  80. // value.
  81. if(typeof a == "string"){ a = a.split(""); }
  82. o = o || win.global; f = df.lambda(f);
  83. for(var i = a.length; i > 0; --i, z = f.call(o, z, a[i], i, a));
  84. return z; // Object
  85. },
  86. foldr1: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){
  87. // summary: repeatedly applies a binary function to an array from right
  88. // to left; returns the final value.
  89. if(typeof a == "string"){ a = a.split(""); }
  90. o = o || win.global; f = df.lambda(f);
  91. var n = a.length, z = a[n - 1], i = n - 1;
  92. for(; i > 0; --i, z = f.call(o, z, a[i], i, a));
  93. return z; // Object
  94. },
  95. // JS 1.8 standard array functions, which can take a lambda as a parameter.
  96. reduce: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ z){
  97. // summary: apply a function simultaneously against two values of the array
  98. // (from left-to-right) as to reduce it to a single value.
  99. return arguments.length < 3 ? df.foldl1(a, f) : df.foldl(a, f, z); // Object
  100. },
  101. reduceRight: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ z){
  102. // summary: apply a function simultaneously against two values of the array
  103. // (from right-to-left) as to reduce it to a single value.
  104. return arguments.length < 3 ? df.foldr1(a, f) : df.foldr(a, f, z); // Object
  105. },
  106. // the fold's counterpart: unfold
  107. unfold: function(/*Function|String|Array*/ pr, /*Function|String|Array*/ f,
  108. /*Function|String|Array*/ g, /*Object*/ z, /*Object?*/ o){
  109. // summary: builds an array by unfolding a value
  110. o = o || win.global; f = df.lambda(f); g = df.lambda(g); pr = df.lambda(pr);
  111. var t = [];
  112. for(; !pr.call(o, z); t.push(f.call(o, z)), z = g.call(o, z));
  113. return t; // Array
  114. }
  115. });
  116. });