Tag Archives: Array

PHP Snippet – array_splice_assoc(…)

Recently I was working on something that required inserting key-value pairs into an array after a specific key in PHP. As I was looking through stackoverflow answers I realized that there was no awesome answer that really jumped out at me. Therefore I decided to take a few minutes to just write my own array_splice_assoc() function to get the job done:

As you can see this function takes the same parameters that array_splice() does but the difference is that the offset can be a string in this key which refers to the key after which the new array elements should be inserted.

One important thing to note is that if you try to insert a key-value pair in which the key exists before or at the offset, your key-value pair will not be inserted. On the other hand if you try to insert a key-value pair in which the key exists after offset, your value will replace the previous one.

Have fun! :cool:

JavaScript – Getting Function Parameter Names

Two years ago I wrote a post about how to pass arguments by name in JavaScript. Recently I have started to ramp a new project call YourJS and found a need to be able to read the names of the parameters of the given function. The following getParamNames() function takes an arbitrary function and returns an array of its parameter names:

Using this function is quite simple. Let’s say that getParamNames() and the function below are defined:

function repeat(string, times, opt_delimiter) {
  opt_delimiter = arguments.length > 2 ? opt_delimiter + '' : '';
  return new Array(times + 1).join(opt_delimiter + string).replace(opt_delimiter, '');
}

Running getParamNames(repeat) will result in the following:

>>> getParamNames(repeat)
["string", "times", "opt_delimiter"]

Running getParamNames(getParamNames) will result in the following:

>>> getParamNames(getParamNames)
["fn"]

Pretty cool, right?!?! Have fun! :cool:

Python Quirks – List Concatenation or Mutation?

If you execute the following code, what do you think will be the result?

list1 = [1]
list2 = list1

list2 += [2, 3]
assert list1 == list2, '{} != {}'.format(list1, list2)

list1 = list1 + [4, 5]
assert list1 == list2, '{} != {}'.format(list1, list2)

Will an assert error occur? The answer is yes! The reason why is because list1 = list1 + list2 is actually different from list1 += list2 in Python. Let’s see what happened when I ran the above code in the command prompt:

>>> list1 = [1]
>>> list2 = list1
>>> 
>>> list2 += [2, 3]
>>> assert list1 == list2, '{} != {}'.format(list1, list2)
>>> 
>>> list1 = list1 + [4, 5]
>>> assert list1 == list2, '{} != {}'.format(list1, list2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: [1, 2, 3, 4, 5] != [1, 2, 3]

As is shown above, using `+=` is not assigning a concatenation of the two lists, but actually mutating the left-hand side list (list1). In other words, list1 += list2 is the same as list1.extend(list2). Interesting, right? :cool:

Python Snippet – Get List Item or Get Default

One of the many cool things about Python is that you can often use builtin functions to either get a value from a dictionary (or an object with getattr) or default to a specified value. Unfortunately lists do not provide such a function. The simplest use case would be to get the first value out of any list if it exists and if not simply return None. After fiddling around with a few different implementations, I landed on this one:

def get_at(list, index, default=None):
  return list[index] if max(~index, index) < len(list) else default

The above function can be used in order to either return the value at the specified index or a default value if the index doesn't exist:

lists = [[], ['Hello world!!!'], range(10)[3:]]

for list in lists:
  print 'list = {}'.format(list)
  print '- first value: {}'.format(get_at(list, 0))
  print '- second value: {}'.format(get_at(list, 1))
  print '- last value: {}'.format(get_at(list, -1))
  print '- 5th value (defaults to "missing"): {}'.format(get_at(list, 4, 'missing'))
  print ''

The above code outputs the following:

list = []
- first value: None
- second value: None
- last value: None
- 5th value (defaults to "missing"): missing

list = ['Hello world!!!']
- first value: Hello world!!!
- second value: None
- last value: Hello world!!!
- 5th value (defaults to "missing"): missing

list = [3, 4, 5, 6, 7, 8, 9]
- first value: 3
- second value: 4
- last value: 9
- 5th value (defaults to "missing"): 7

You may be thinking that there must be another way to do this. There are in fact various other ways to do this. One of them is to use `next(iter(list[index:]), default)` as the return value. The main reason I landed on the solution that uses max() and a ternary statement is because I wanted to minimize the amount of objects created. Using next() along with iter() requires a generator to be created for the sliced list. On the other hand, Python handles all of this pretty efficiently so its possible that the difference between the two solutions is minimal. Either way, now I have a succinct helper function that either gets me a list item or the default value I specify. :cool:

JavaScript Quirks – Array Slicing Node Lists

For a while many developers, including myself, suggested that Array.prototype.slice() be used to turn any array-like object into an array. Recently, I was alerted to a scenario in which this does not work as expected. Let’s take the following code for example:

var elems = document.body.getElementsByTagName('*');
var arrElems = Array.prototype.slice.call(elems, 0);

In most browsers, the above code would take the node list assigned to elems and create an array of those nodes and assign it to arrElems. Leave it to Internet Explorer to be the exception, right? Unfortunately, Internet Explorer 8 and lower throw a run-time error: JScript object expected.

For that reason, functions that are written to reliably turn array-like objects into arrays should use the good old-fashioned loop in order to accomplish the task:

function makeArray(o) {
  for (var i = 0, l = o.length, a = new Array(i); i < l; i++) {
    if (i in o) {
      a[i] = o[i];
    }
  }
  return a;
}

As you will notice, the above function creates an array of the same length and only adds the values where found (just as slice() does when copying arrays).

It might be argued that using hasOwnProperty() is a faster solution, but after doing this performance test it seems that the fastest implementation depends on the browser. On the other hand, going in reverse order seemed generally slightly slower. Therefore, I decided to settle with the above implementation which can be finely tuned depending on the target environment. Of course, you could use slice() and then if it fails, fall back to the for loop:

function makeArray(o) {
  try {
    return Array.prototype.slice.call(o);
  } catch (e) {}
  
  for (var i = 0, l = o.length, a = new Array(i); i < l; i++) {
    if (i in o) {
      a[i] = o[i];
    }
  }
  return a;
}

The aforementioned performance test shows that this solution is actually one of the more performant solutions across browsers. In the end it is all up to you. Have fun! :cool:

JavaScript Snippet – Get Function Comments

Last year I wrote about having heredoc like strings available in JavaScript. Today I figured i’d briefly bring the topic back, providing a solution for returning an array of all comments found in a function:

Why is this useful? As you may know, writing multiline strings in JavaScript isn’t always the prettiest especially when you have to use \n or \r\n. On the other hand, let’s imagine that we have some multiline strings stored inside of a function as comments:

As you can see in the above jPaq Proof, by using the getComments function on a function which contains comments you can pull the comments out as if they were HEREDOC strings. Have fun! 8-)

NOTE: It is important to remember that if you are minifying your code, these comments will most-likely be stripped out. In this case you will want to find a different solution such as using the string escape characters (\r\n or \n).

JavaScript Snippet – Fancy getKeys

Most of us know the simple way to get the keys from an object in JavaScript (~61 bytes after minified):

function getKeys(obj) {
    var k = [];
    for (var i in obj) {
        k.push(i);
    }
    return k;
}

But how many of us knew that array assignment within the for-in loop would work? (~58 bytes after minified)

function getKeys(obj) {
    var i = 0, k = [];
    for (k[i++] in obj) {}
    return k;
}

To be honest I cant take the credit for this because I actually found it here. Even though knowing this may rarely help you shorten your code, this is still a pretty cool capability! 8-)

WARNINGS:

  • The above defined getKeys function is really just to prove that you can do for(anArray[counter++] in anObject)....
  • If you can be certain that Object.keys will be defined in the environment in which your code will run, you should use that native function instead.
  • Using this function as is will include prototypal properties defined for the class of the object passed.
  • This function will not return properties that override prototypal properties (such as toString) in some environments.

Excel – Multi-column VLookup

When analyzing data in Excel at times it is necessary to pull data from another data source based on more than one column. In this case you can use the MATCH function in an array formula. Just so you understand the general idea of an array, it is a collection of values. The match function is generally used to find a value in an array. Knowing this, we will use this Excel file to show how to engineer a multi-column VLOOKUP in a few simple steps.

Source Data Tab

Above is a screenshot of the data in the Source Data tab. On our Lookups tab I started off with just the first names and last names of some users. In order to pull the corresponding usernames and DOBs (dates of birth) I did the following:

  1. Setup a column indicating where the matching data was found by using the following array formula:
    {=MATCH(1,('Source Data'!$A$2:$A$27=$A1)*('Source Data'!$B$2:$B$27=$B1),0)}

    • It is important to note that even though the formula is surrounded by curly braces, those are put there by Excel (NOT MANUALLY) when executing the formula by using the CTRL+SHIFT+ENTER key combination.
    • The first parameter (1) indicates the value being searched for in the second parameter.
    • The second parameter is an array which remains such only because of the CTRL+SHIFT+ENTER key combination used to finalize the formula.

      • That will produce an array of 0s and 1s which are coerced into the numbers because of the multiplication operation.
      • If there was only one column checked and the multiplication were taken out, the array will be full of TRUEs and FALSEs. For example the formula=TRUE*TRUE results in 1 while TRUE*FALSE results in 0.
    • The third parameter 0 indicates that the first parameter must match be an exact match of one of the items in the array (second parameter).
    • The value returned will be the position (start at 1) of the value in the array if found. If not found an N/A error will be returned.
  2. Setup a new column which references the matching row column to pull the corresponding username if a matching row was found. If the row wasn’t found show the cell as empty:
    =IF(ISNA($C2),"",INDEX('Source Data'!$C$2:$C$27,$C2))
  3. Setup a new column which references the matching row column to pull the corresponding DOB if a matching row was found. Format the date using the YYYY-MM-DD format. If the row wasn’t found show the cell as empty:
    =IF(ISNA($C2),"",TEXT(INDEX('Source Data'!$D$2:$D$27,$C2),"YYYY-MM-DD"))

After doing the above three steps in row 2 of the Lookups sheet and copying the formulas down, the final result was this:

Lookups Tab

If I were to clean this up a bit more I might hide column C of the Lookups tab, but other than that there really isn’t much else you need to do. I know this may still seem a bit mysterious, but with practice you will begin to understand array formulas better and perhaps write other useful array formulas to get the job done. For all of you who came to figure out how to do a multi-criteria lookup, I hoped it helped but if not, comment on what needs clarifying and I will do my best to help. 8-)

PHP – Foreach By Reference

Today I was writing some code in which I wanted to modify the values of an array within a for-loop. The obvious solution would be to use the key to modify the value but there is actually another way of doing it:

$arr = array(1,2,3,4,5);
foreach ($arr as &$value) {
  $value = $value * $value;
}
print_r($arr);

The above code will actually go through the array of integers 1 to 5 and change the array to be the squares of those values. The output is as follows:

Array
(
    [0] => 1
    [1] => 4
    [2] => 9
    [3] => 16
    [4] => 25
)

This works because placing the ampersand in front of the $value makes the variable refer to the actual value within the array and updating it will update the value within the array.

JavaScript – Parsing A Number

If you should ever need to parse a number into an array of bits or a different base you can use the following function:

var splitNumber = (function(MAX) {
  for (; MAX + 1 - MAX == 1; MAX *= 2){}
  return function (num, radix) {
    // Validate num
    num = parseInt(num, 10);
    if (!isFinite(num) || 0 > num || num > MAX) {
      throw new Error('splitNumber() num argument must be a non-negative finite number less than ' + MAX);
    }
 
    // Validate radix
    radix = parseInt(radix || 10, 10);
    if (!(1 < radix && radix <= MAX)) {  // Also prevents NaN
      throw new Error('splitNumber() radix argument must be greater than 2 and less than ' + MAX);
    }
 
    return num.toString(radix).split('');
  };
})(1 << 30);

Here is an example of the tests and outputs:

I want to thank ildar for contributing the refinement of this function. 8-)