Version 3.18.1
Show:

File: collection/js/array-extras.js

  1. /**
  2. Adds additional utility methods to the `Y.Array` class.
  3. @module collection
  4. @submodule array-extras
  5. **/
  6. var A = Y.Array,
  7. L = Y.Lang,
  8. ArrayProto = Array.prototype;
  9. /**
  10. Returns the index of the last item in the array that contains the specified
  11. value, or `-1` if the value isn't found.
  12. @method lastIndexOf
  13. @param {Array} a Array to search in.
  14. @param {Any} val Value to search for.
  15. @param {Number} [fromIndex] Index at which to start searching backwards.
  16. Defaults to the array's length - 1. If negative, it will be taken as an offset
  17. from the end of the array. If the calculated index is less than 0, the array
  18. will not be searched and `-1` will be returned.
  19. @return {Number} Index of the item that contains the value, or `-1` if not
  20. found.
  21. @static
  22. @for Array
  23. **/
  24. A.lastIndexOf = L._isNative(ArrayProto.lastIndexOf) ?
  25. function(a, val, fromIndex) {
  26. // An undefined fromIndex is still considered a value by some (all?)
  27. // native implementations, so we can't pass it unless it's actually
  28. // specified.
  29. return fromIndex || fromIndex === 0 ? a.lastIndexOf(val, fromIndex) :
  30. a.lastIndexOf(val);
  31. } :
  32. function(a, val, fromIndex) {
  33. var len = a.length,
  34. i = len - 1;
  35. if (fromIndex || fromIndex === 0) {
  36. i = Math.min(fromIndex < 0 ? len + fromIndex : fromIndex, len);
  37. }
  38. if (i > -1 && len > 0) {
  39. for (; i > -1; --i) {
  40. if (i in a && a[i] === val) {
  41. return i;
  42. }
  43. }
  44. }
  45. return -1;
  46. };
  47. /**
  48. Returns a copy of the input array with duplicate items removed.
  49. Note: If the input array only contains strings, the `Y.Array.dedupe()` method is
  50. a much faster alternative.
  51. @method unique
  52. @param {Array} array Array to dedupe.
  53. @param {Function} [testFn] Custom function to use to test the equality of two
  54. values. A truthy return value indicates that the values are equal. A falsy
  55. return value indicates that the values are not equal.
  56. @param {Any} testFn.a First value to compare.
  57. @param {Any} testFn.b Second value to compare.
  58. @param {Number} testFn.index Index of the current item in the original
  59. array.
  60. @param {Array} testFn.array The original array.
  61. @return {Boolean} _true_ if the items are equal, _false_ otherwise.
  62. @return {Array} Copy of the input array with duplicate items removed.
  63. @static
  64. **/
  65. A.unique = function (array, testFn) {
  66. var i = 0,
  67. len = array.length,
  68. results = [],
  69. j, result, resultLen, value;
  70. // Note the label here. It's used to jump out of the inner loop when a value
  71. // is not unique.
  72. outerLoop: for (; i < len; i++) {
  73. value = array[i];
  74. // For each value in the input array, iterate through the result array
  75. // and check for uniqueness against each result value.
  76. for (j = 0, resultLen = results.length; j < resultLen; j++) {
  77. result = results[j];
  78. // If the test function returns true or there's no test function and
  79. // the value equals the current result item, stop iterating over the
  80. // results and continue to the next value in the input array.
  81. if (testFn) {
  82. if (testFn.call(array, value, result, i, array)) {
  83. continue outerLoop;
  84. }
  85. } else if (value === result) {
  86. continue outerLoop;
  87. }
  88. }
  89. // If we get this far, that means the current value is not already in
  90. // the result array, so add it.
  91. results.push(value);
  92. }
  93. return results;
  94. };
  95. /**
  96. Executes the supplied function on each item in the array. Returns a new array
  97. containing the items for which the supplied function returned a truthy value.
  98. @method filter
  99. @param {Array} a Array to filter.
  100. @param {Function} f Function to execute on each item.
  101. @param {Object} [o] Optional context object.
  102. @return {Array} Array of items for which the supplied function returned a
  103. truthy value (empty if it never returned a truthy value).
  104. @static
  105. */
  106. A.filter = L._isNative(ArrayProto.filter) ?
  107. function(a, f, o) {
  108. return ArrayProto.filter.call(a, f, o);
  109. } :
  110. function(a, f, o) {
  111. var i = 0,
  112. len = a.length,
  113. results = [],
  114. item;
  115. for (; i < len; ++i) {
  116. if (i in a) {
  117. item = a[i];
  118. if (f.call(o, item, i, a)) {
  119. results.push(item);
  120. }
  121. }
  122. }
  123. return results;
  124. };
  125. /**
  126. The inverse of `Array.filter()`. Executes the supplied function on each item.
  127. Returns a new array containing the items for which the supplied function
  128. returned `false`.
  129. @method reject
  130. @param {Array} a the array to iterate.
  131. @param {Function} f the function to execute on each item.
  132. @param {object} [o] Optional context object.
  133. @return {Array} The items for which the supplied function returned `false`.
  134. @static
  135. */
  136. A.reject = function(a, f, o) {
  137. return A.filter(a, function(item, i, a) {
  138. return !f.call(o, item, i, a);
  139. });
  140. };
  141. /**
  142. Executes the supplied function on each item in the array. Iteration stops if the
  143. supplied function does not return a truthy value.
  144. @method every
  145. @param {Array} a the array to iterate.
  146. @param {Function} f the function to execute on each item.
  147. @param {Object} [o] Optional context object.
  148. @return {Boolean} `true` if every item in the array returns `true` from the
  149. supplied function, `false` otherwise.
  150. @static
  151. */
  152. A.every = L._isNative(ArrayProto.every) ?
  153. function(a, f, o) {
  154. return ArrayProto.every.call(a, f, o);
  155. } :
  156. function(a, f, o) {
  157. for (var i = 0, l = a.length; i < l; ++i) {
  158. if (i in a && !f.call(o, a[i], i, a)) {
  159. return false;
  160. }
  161. }
  162. return true;
  163. };
  164. /**
  165. Executes the supplied function on each item in the array and returns a new array
  166. containing all the values returned by the supplied function.
  167. @example
  168. // Convert an array of numbers into an array of strings.
  169. Y.Array.map([1, 2, 3, 4], function (item) {
  170. return '' + item;
  171. });
  172. // => ['1', '2', '3', '4']
  173. @method map
  174. @param {Array} a the array to iterate.
  175. @param {Function} f the function to execute on each item.
  176. @param {object} [o] Optional context object.
  177. @return {Array} A new array containing the return value of the supplied function
  178. for each item in the original array.
  179. @static
  180. */
  181. A.map = L._isNative(ArrayProto.map) ?
  182. function(a, f, o) {
  183. return ArrayProto.map.call(a, f, o);
  184. } :
  185. function(a, f, o) {
  186. var i = 0,
  187. len = a.length,
  188. results = ArrayProto.concat.call(a);
  189. for (; i < len; ++i) {
  190. if (i in a) {
  191. results[i] = f.call(o, a[i], i, a);
  192. }
  193. }
  194. return results;
  195. };
  196. /**
  197. Executes the supplied function on each item in the array, "folding" the array
  198. into a single value.
  199. @method reduce
  200. @param {Array} a Array to iterate.
  201. @param {Any} init Initial value to start with.
  202. @param {Function} f Function to execute on each item. This function should
  203. update and return the value of the computation. It will receive the following
  204. arguments:
  205. @param {Any} f.previousValue Value returned from the previous iteration,
  206. or the initial value if this is the first iteration.
  207. @param {Any} f.currentValue Value of the current item being iterated.
  208. @param {Number} f.index Index of the current item.
  209. @param {Array} f.array Array being iterated.
  210. @param {Object} [o] Optional context object.
  211. @return {Any} Final result from iteratively applying the given function to each
  212. element in the array.
  213. @static
  214. */
  215. A.reduce = L._isNative(ArrayProto.reduce) ?
  216. function(a, init, f, o) {
  217. // ES5 Array.reduce doesn't support a thisObject, so we need to
  218. // implement it manually.
  219. return ArrayProto.reduce.call(a, function(init, item, i, a) {
  220. return f.call(o, init, item, i, a);
  221. }, init);
  222. } :
  223. function(a, init, f, o) {
  224. var i = 0,
  225. len = a.length,
  226. result = init;
  227. for (; i < len; ++i) {
  228. if (i in a) {
  229. result = f.call(o, result, a[i], i, a);
  230. }
  231. }
  232. return result;
  233. };
  234. /**
  235. Executes the supplied function on each item in the array, searching for the
  236. first item that matches the supplied function.
  237. @method find
  238. @param {Array} a the array to search.
  239. @param {Function} f the function to execute on each item. Iteration is stopped
  240. as soon as this function returns `true`.
  241. @param {Object} [o] Optional context object.
  242. @return {Object} the first item that the supplied function returns `true` for,
  243. or `null` if it never returns `true`.
  244. @static
  245. */
  246. A.find = function(a, f, o) {
  247. for (var i = 0, l = a.length; i < l; i++) {
  248. if (i in a && f.call(o, a[i], i, a)) {
  249. return a[i];
  250. }
  251. }
  252. return null;
  253. };
  254. /**
  255. Iterates over an array, returning a new array of all the elements that match the
  256. supplied regular expression.
  257. @method grep
  258. @param {Array} a Array to iterate over.
  259. @param {RegExp} pattern Regular expression to test against each item.
  260. @return {Array} All the items in the array that produce a match against the
  261. supplied regular expression. If no items match, an empty array is returned.
  262. @static
  263. */
  264. A.grep = function(a, pattern) {
  265. return A.filter(a, function(item, index) {
  266. return pattern.test(item);
  267. });
  268. };
  269. /**
  270. Partitions an array into two new arrays, one with the items for which the
  271. supplied function returns `true`, and one with the items for which the function
  272. returns `false`.
  273. @method partition
  274. @param {Array} a Array to iterate over.
  275. @param {Function} f Function to execute for each item in the array. It will
  276. receive the following arguments:
  277. @param {Any} f.item Current item.
  278. @param {Number} f.index Index of the current item.
  279. @param {Array} f.array The array being iterated.
  280. @param {Object} [o] Optional execution context.
  281. @return {Object} An object with two properties: `matches` and `rejects`. Each is
  282. an array containing the items that were selected or rejected by the test
  283. function (or an empty array if none).
  284. @static
  285. */
  286. A.partition = function(a, f, o) {
  287. var results = {
  288. matches: [],
  289. rejects: []
  290. };
  291. A.each(a, function(item, index) {
  292. var set = f.call(o, item, index, a) ? results.matches : results.rejects;
  293. set.push(item);
  294. });
  295. return results;
  296. };
  297. /**
  298. Creates an array of arrays by pairing the corresponding elements of two arrays
  299. together into a new array.
  300. @method zip
  301. @param {Array} a Array to iterate over.
  302. @param {Array} a2 Another array whose values will be paired with values of the
  303. first array.
  304. @return {Array} An array of arrays formed by pairing each element of the first
  305. array with an item in the second array having the corresponding index.
  306. @static
  307. */
  308. A.zip = function(a, a2) {
  309. var results = [];
  310. A.each(a, function(item, index) {
  311. results.push([item, a2[index]]);
  312. });
  313. return results;
  314. };
  315. /**
  316. Flattens an array of nested arrays at any abitrary depth into a single, flat
  317. array.
  318. @method flatten
  319. @param {Array} a Array with nested arrays to flatten.
  320. @return {Array} An array whose nested arrays have been flattened.
  321. @static
  322. @since 3.7.0
  323. **/
  324. A.flatten = function(a) {
  325. var result = [],
  326. i, len, val;
  327. // Always return an array.
  328. if (!a) {
  329. return result;
  330. }
  331. for (i = 0, len = a.length; i < len; ++i) {
  332. val = a[i];
  333. if (L.isArray(val)) {
  334. // Recusively flattens any nested arrays.
  335. result.push.apply(result, A.flatten(val));
  336. } else {
  337. result.push(val);
  338. }
  339. }
  340. return result;
  341. };