Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

About this user

Keith Gaughan http://talideon.com/

« Newer Snippets
Older Snippets »
Showing 1-10 of 11 total  RSS 

Flattening an array of arrays in PHP

It does just what it says on the tin:
   1  
   2  /** Denests the nested arrays within the given array. */
   3  function flatten_array(array $a) {
   4      $i = 0;
   5      while ($i < count($a)) {
   6          if (is_array($a[$i])) {
   7              array_splice($a, $i, 1, $a[$i]);
   8          } else {
   9              $i++;
  10          }
  11      }
  12      return $a;
  13  }

With added unit-testy goodness:
   1  
   2  class FlattenTest extends PHPUnit_Framework_TestCase {
   3  
   4      public function test_flatten() {
   5          $this->assertEquals(array(), flatten_array(array()));
   6          $this->assertEquals(array(1), flatten_array(array(1)));
   7          $this->assertEquals(array(1), flatten_array(array(array(1))));
   8          $this->assertEquals(array(1, 2), flatten_array(array(array(1, 2))));
   9          $this->assertEquals(array(1, 2), flatten_array(array(array(1), 2)));
  10          $this->assertEquals(array(1, 2), flatten_array(array(1, array(2))));
  11          $this->assertEquals(array(1, 2, 3), flatten_array(array(1, array(2), 3)));
  12          $this->assertEquals(array(1, 2, 3, 4), flatten_array(array(1, array(2, 3), 4)));
  13      }
  14  }

Value coalescence in PHP

Here's something I keep on having to do in PHP and other languages. Often I need to find the first non-empty value from a set of arguments. Here's how I do it.
   1  
   2  function coalesce() {
   3      $args = func_get_args();
   4      foreach ($args as $arg) {
   5          if (!empty($arg)) {
   6              return $arg;
   7          }
   8      }
   9      return $args[0];
  10  }

The function assumes that it will be called with at least one value. It can be trivially altered to use is_null() instead if that suits.

Clean magic quoting in ColdFusion 5 and later

I'm updating my weblog software and needed some code to properly convert typewriter quotes to proper typographer's quotes.

   1  
   2  <cfscript>
   3  function magicQuote(txt) {
   4      // Left quotes
   5      txt = REReplace(txt, "(^|[ " & Chr(9) & Chr(10) & Chr(13) & "'])""", "\1&##8220;", "ALL");
   6      txt = REReplace(txt, "(^|[ " & Chr(9) & Chr(10) & Chr(13) & "]|&##8220;)'",  "\1&##8216;", "ALL");
   7  
   8      // Right quotes
   9      txt = Replace(txt, """",        "&##8221;",  "ALL");
  10      txt = Replace(txt, "'&##8220;", "'&##8221;", "ALL");
  11      txt = Replace(txt, "'",         "&##8217;",  "ALL");
  12  
  13      return txt;
  14  }
  15  </cfscript>

ColdFusion 5 has problems with \s, and the character class is a workaround for this.

Gaussian/Banker's Rounding

Gaussian rounding (aka Banker's rounding) rounds numbers in such a way as there is no upwards bias when rounding x.5. This minimises cumulative error in summing, averaging, &c. rounded numbers.

   1  
   2  /**
   3   * Gaussian rounding (aka Banker's rounding) is a method of statistically
   4   * unbiased rounding. It ensures against bias when rounding at x.5 by
   5   * rounding x.5 towards the nearest even number. Regular rounding has a
   6   * built-in upwards bias.
   7   */
   8  function gaussianRound(x) {
   9      var absolute = Math.abs(x);
  10      var sign     = x == 0 ? 0 : (x < 0 ? -1 : 1);
  11      var floored  = Math.floor(absolute);
  12      if (absolute - floored != 0.5) {
  13          return Math.round(absolute) * sign;
  14      }
  15      if (floored % 2 == 1) {
  16          // Closest even is up.
  17          return Math.ceil(absolute) * sign;
  18      }
  19      // Closest even is down.
  20      return floored * sign;
  21  }


Thanks to Dennis W Jay for pointing out a bug in the code.

Generating a shuffled array.

Adds a method to Array to return a shuffled version of the array.

   1  
   2  if (!Array.prototype.shuffle) {
   3      Array.prototype.shuffle = function() {
   4          // Clone this array.
   5          var result = this.concat();
   6  
   7          // Swap each element with another randomly selected one.
   8          for (var i = 0; i < result.length; i++) {
   9              var j = i;
  10              while (j == i) {
  11                  j = Math.floor(Math.random() * result.length);
  12              }
  13              var contents = result[i];
  14              result[i]    = arr[j];
  15              result[j]    = contents;
  16          }
  17  
  18          return result;
  19      };
  20  }

JavaScript versions of the functions described in Martin Fowler's article "CollectionClosureMethod"

See the original article at http://www.martinfowler.com/bliki/CollectionClosureMethod.html.

These implement all the methods except the sorting related ones.
   1  
   2  Array.prototype.select = function(detect) {
   3      var result = [];
   4      for (var i = 0; i < this.length; ++i) {
   5          if (detect(this[i])) {
   6              result.push(this[i]);
   7          }
   8      }
   9      return result;
  10  };
  11  
  12  Array.prototype.reject = function(detect) {
  13      var result = [];
  14      for (var i = 0; i < this.length; ++i) {
  15          if (!detect(this[i])) {
  16              result.push(this[i]);
  17          }
  18      }
  19      return result;
  20  };
  21  
  22  Array.prototype.partition = function(detect) {
  23      var yeses = [];
  24      var nos   = [];
  25      for (var i = 0; i < this.length; ++i) {
  26          if (detect(this[i])) {
  27              yeses.push(this[i]);
  28          } else {
  29              nos.push(this[i]);
  30          }
  31      }
  32      return [yeses, nos];
  33  };
  34  
  35  Array.prototype.all = function(detect) {
  36      for (var i = 0; i < this.length; ++i) {
  37          if (!detect(this[i])) {
  38              return false;
  39          }
  40      }
  41      return true;
  42  };
  43  
  44  Array.prototype.any = function(detect) {
  45      for (var i = 0; i < this.length; ++i) {
  46          if (detect(this[i])) {
  47              return true;
  48          }
  49      }
  50      return false;
  51  };
  52  
  53  Array.prototype.find = function(detect, ifNone) {
  54      for (var i = 0; i < this.length; ++i) {
  55          if (detect(this[i])) {
  56              return this[i];
  57          }
  58      }
  59  
  60      if (ifNone === null) {
  61          return null;
  62      }
  63  
  64      return ifNone();
  65  };
  66  
  67  Array.prototype.map = function(mapper) {
  68      var result = [];
  69      for (var i = 0; i < this.length; ++i) {
  70          result.push(mapper(this[i]));
  71      }
  72      return result;
  73  };
  74  
  75  Array.prototype.inject = function(initial, reducer) {
  76      var result = initial;
  77      for (var i = 0; i < this.length; ++i) {
  78          result = reducer(result, this[i]);
  79      }
  80      return result;
  81  };

An analogue of ColdFusion's CFPARAM tag in PHP.

   1  
   2  /**
   3   * Checks if $var is already defined and if not, sets it to
   4   * $default.
   5   *
   6   * @param  $var         Variable to check.
   7   * @param  $default     Value to give the checked variable if
   8   *                      found to be null; "" by default.
   9   * @param  $catchNulls  TRUE: treat empty strings as null; FALSE
  10   *                      by default.
  11   *
  12   * @note   It's a lot like ColdFusion's <CFPARAM> tag.
  13   */
  14  function set_default(&$var, $default="", $catchNulls=FALSE) {
  15      if (!isset($var) || ($catchNulls && $var == "")) {
  16          $var = $default;
  17      }
  18  }

This appears to have stopped working as of PHP 5.

The world's simplest (decent) PHP templating engine...

...is PHP, so why not use it?
   1  
   2  function include_view($__view, $vars=NULL) {
   3      # Start buffering the generated text.
   4      ob_start();
   5  
   6      # Process the view.
   7      if (!is_null($vars)) {
   8          extract($vars, EXTR_OVERWRITE | EXTR_REFS);
   9      }
  10      include("views/$__view.php");
  11  
  12      # Grab the generated content and clean up.
  13      $content = ob_get_contents();
  14      ob_end_clean();
  15  
  16      return $content;
  17  }

Memoizing functions in JavaScript

Here's something I knocked together a fortnight ago because I wanted to see if I could produce Perl's Memoize.pm in JavaScript.

Memoization is a method of increasing the speed of slow referentially transparent functions by caching their arguments and results. This trades a marginal amount of memory space for a potentially huge gain in speed.

Take the canonical definition of the fibonacci sequence, for instance:
   1  
   2  function fib(n) {
   3      if (n < 2) {
   4          return n;
   5      }
   6      return fib(n - 1) + fib(n - 2);
   7  }

As you can guess, this quickly becomes quite slow once you start using numbers greater than around 20. Once you're dealing with numbers in the mid-thirties range, it cripples the computer.

The solution is to memoize the function. You can either do it by hand:
   1  
   2  var iterMemoFib = (function() {
   3      var cache = [1, 1];
   4      var fib = function(n) {
   5          if (n >= cache.length) {
   6              for (var i = cache.length; i <= n; i++) {
   7                  cache[i] = cache[i - 2] + cache[i - 1];
   8              }
   9          }
  10          return cache[n];
  11      }
  12  
  13      return fib;
  14  })();

Which is a wee bit of a pain and not exactly readable; or get the computer to do it for you:
   1  
   2  fib = fib.memoize();

Due to technical (browser security) constraints, the arguments for memoized functions can only be arrays or scalar values. No objects.

The code extends the Function object to add the memoization functionality. If the function is a method, then you can pass the object into memoize().
   1  
   2  Function.prototype.memoize = function() {
   3      var pad  = {};
   4      var self = this;
   5      var obj  = arguments.length > 0 ? arguments[i] : null;
   6  
   7      var memoizedFn = function() {
   8          // Copy the arguments object into an array: allows it to
   9          // be used as a cache key.
  10          var args = [];
  11          for (var i = 0; i < arguments.length; i++) {
  12              args[i] = arguments[i];
  13          }
  14  
  15          // Evaluate the memoized function if it hasn't been
  16          // evaluated with these arguments before.
  17          if (!(args in pad)) {
  18              pad[args] = self.apply(obj, arguments);
  19          }
  20  
  21          return pad[args];
  22      }
  23  
  24      memoizedFn.unmemoize = function() {
  25          return self;
  26      }
  27  
  28      return memoizedFn;
  29  }
  30  
  31  Function.prototype.unmemoize = function() {
  32      alert("Attempt to unmemoize an unmemoized function.");
  33      return null;
  34  }

Removing duplicates from lists

A request for this came up on the CF-Talk list recently. Here's what I came up with.
   1  
   2  <!--- The list with want to clean up --->
   3  <cfset lst = "a,list,with,a,few,duplicates">
   4  <!--- Use a struct to build a set of the list elements --->
   5  <cfset set = StructNew()>
   6  <cfloop index="elem" list="#lst#">
   7      <cfset set[elem] = "">
   8  </cfloop>
   9  <!--- Convert the set back to a list --->
  10  <cfset lst = StructKeyList(set)>

This sort of this should be familiar to all you perlmongers out there.
« Newer Snippets
Older Snippets »
Showing 1-10 of 11 total  RSS