fold.js 4.7 KB

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