TweetFollow Us on Twitter

Associative Arrays

Volume Number: 16 (2000)
Issue Number: 10
Column Tag: Programming Techniques

How to Harness the Power of Associative Arrays

by Kas Thomas

A widely underutilized technique can go a long way toward making your code smaller, more reliable, and easier to maintain, whether you program in C, Java, or JavaScript

Fostering reliability, maintainability, compactness, and good performance in code has been a constant quest for programmers and language designers over the years. It's rare that one technique can give you all of the above benefits, concurrently. But intelligent use of associative arrays can do that. If you haven't yet tapped into the power of associative arrays, you might want to give the issues involved some thought. The issues are widely applicable to a variety of programming tasks, cutting across all major languages.

One thing's for sure. If you use a lot of switch statements in your code (to "case out" user-selected actions, for example), you're sitting on a great opportunity to improve the reliability and maintainability of your code; just follow along and see.

What Is an Associative Array?

An associative array is a collection of data values in which access to any particular value is obtained via a (single) key. Generally speaking, it's a one-to-one mapping of data entities ("values") to keys, such that no two values map to the same key (although two different keys could, coincidentally, contain the same value). For example, in an array of TV listings, you might very well find that two different channels are showing the same episode of Gilligan's Island at 4:00 a.m. Tuesday, but you would never find Channel 2 listed twice, showing two different shows in the same time slot.

In a larger sense, associative-array mapping is an application of set theory, and languages that have a robust collections package will invariably implement some form of associative-array mapping.

For a quick example of an associative array, consider the hypothetical entity in Figure 1.

Figure 1. A hypothetical associative array.

In this example, we have an anonymous (nameless) array of tuples shown as keys mapped to values. The itemType key, for example, maps to the value 'auto'. If this were a conventional (ordered) array, we would say that the zeroth item in the array is the (string) value 'auto', the first item is '4WD', etc.

For the array shown in Figure 1 to be useful, we need to be able to hold a reference to the array in a variable, and we need to have a syntax for obtaining the value of each member, given the value of the corresponding key. It would also be nice if we could find out how many items are in the array (since it might be arbitrarily large) and to know how to iterate through the members. With an ordered array, you can step through the members in sequence. But in an array like this one, where the keys aren't integers, how do you enumerate the array's contents?

Associative Arrays in JavaScript

Core JavaScript (or ECMAScript) has a convenient syntax for dealing with constructions such as this. (Even if you're not a JavaScript programmer, bear with me here, because I'll be discussing other languages in a moment.) In the world of object-oriented programming, an arbitrary collection of data entities is often called an object. In JavaScript, a generic object is, in fact, an associative array (whose members can be references to functions, in which case those particular members are called methods). In the OOP world, dot notation is commonly used to "index into" an object. For example:

var myObject =   new Object();
myObject.itemType =   'auto';
myObject.subtype =   '4WD';
myObject.make =         'Jeep';
myObject.year =         '1998';
myObject.color =      'green';

In JavaScript, this is an entirely acceptable way to implement the object suggested by Figure 1. An equivalent syntax that uses literal notation is:

var myObject = { 'itemType' :   'auto',
                        'subtype'  :   '4WD',
                         'make'     :   'Jeep',
                         'year'     :   '1998',
                        'color'    :   'green' };

But are we justified in calling this an associative array? Yes, we are, because it turns out we can also use array notation (square brackets) in JavaScript to refer to object properties:

var myObject =   new Object();
myObject['itemType'] =      'auto';
myObject['subtype'] =      '4WD';
myObject['make'] =         'Jeep';
myObject['year'] =         '1998';
myObject['color'] =         'green';

if (myObject['itemType'] ==   'auto' 
  && myObject['make'] ==         'Jeep')       // true
      myObject['subtype'] =      '4WD';   // assign '4WD' to myObject.subtype

In JavaScript, square brackets can substitute for dot notation when referring to object properties. The only proviso is, the enclosed property name must be supplied as a string literal (as shown above). This turns out to be an extremely handy syntactical construct, because it means we are not limited to one-word property names. We can now consider constructions like:

myObject['extended warranty'] = true; // legal myObject['original delivery date'] = '1/1/98'; // legal myObject.'original delivery date' = '1/1/98'; // ERROR!

Iterating through the contents of an associative array (or the properties of an object) would seem to present a problem, since the contents aren't necessarily ordered and can't be "indexed into" numerically. In JavaScript, however, there is a very handy loop syntax for doing this:

var bigstring = new String();

for (var i in myObject)
    bigstring += i + "\n";

The above code builds a list of all the property names in myObject (separated by newlines), concatenating them into a single big string.


Perl has a built-in associative-array construct called the hash. The syntax for creating a hash looks like:

%myObject = ('itemType' , 'auto', 'subtype' , '4WD', 'make' , 'Jeep', 'year' , '1998', 'color' , 'green');

Notice that commas are used throughout the pairs list, rather than the more readable JavaScript technique of putting colons between keys and values (using commas to separate complete tuples).

To access a hash value in Perl, you use a notation that looks like:

$myObject{ 'color' } = 'red';

Notice the seemingly inconsistent use of the dollar sign (instead of the percent sign) and curly braces (instead of parentheses) for accessing individual values of a hash. This is a standard Perl idiom. The percent sign refers only to complete hashes.


With the advent of the Java 2 platform , the java.util package now has a powerful Collections Framework (not to be confused with JGL, the Generic Collections Library for Java by ObjectSpace, which was first-to-market and was widely distributed in IDEs before Sun came out with the J2SE Collections Framework), encompassing sorted and unsorted sets, maps, and lists, plus iterators for same, in thread-safe and non-thread-safe versions. Prior to Java 2, the language had Vector and HashTable classes to accommodate this need, but those classes have been relegated to legacy status. Today, if you need an associative array, you call on the HashMap class, which implements the Map interface:

Map map = new HashMap();
map.put("itemType", "auto");
map.put("subtype" , "4WD");
map.put("make"    , "Jeep");
map.put("year"    , "1998");
map.put("color"   , "green");

For sorted maps, you can create a TreeMap (using a Map as input, if necessary), which stores its elements in an always-balanced tree.

C and C++

In C++, the Standard Template Library provides rich support for collections idioms of all kinds. The map is an associative container that accomplishes the kind of functionality we've been talking about:

map<string,string> myMap;
myMap["itemType"] = "auto";
months["subtype"] = "4WD";

// etc. etc.

To use it, be sure to #include <map>. See any good reference on STL for further details.

ANSI C, on the other hand, has no built-in support for associative arrays. You can craft your own support, of course, with a little effort. But how? As you might guess from the repeated use of the strange term "hash" in this context, implementing an associative array from scratch requires the use of hash techniques.

What, exactly, is a hash? A hash is basically a mathematical function in the canonical sense: a "black box" that maps domain values to range values, with the requirement that any one domain value can map to no more than one range value. This is exactly the mapping behavior we're looking for, of course.

But what does a hash function really look like? The answer is, it can look like whatever you want it to look like, or (more commonly) whatever you need it to look like. If that sounds a bit vague, that's because hash techniques fall into a curious category of computational heuristics with a long background in computer-science lore. In the old days of limited machine resources, you'd use hash techniques to maximize performance while minimizing storage requirements. Good hash functions weren't often published, and if they were, their workings were rarely self-evident.

A Hash-Code Example

A quick example may help. Suppose you are implementing an exception dictionary for a spellchecker: i.e., a special dictionary to store user-entered words. What you want is that when a user types a word that is not in the regular dictionary, the exception dictionary can be consulted; and at that point, you simply need to know whether the word exists in that dictionary. (If not, you flag the word as a possible misspelling and notify the user.) You have a maximum of 5 Kbytes of storage available for this task, because you're running on a 1970s machine with severely limited resources.

A typical answer to this challenge would be to insert exception words into a linked list, and do a lookup by traversing the list. With 5K of storage and an average word length of five characters, you could store as many as 1,000 words in the list (more than adequate for most exception dictionaries). But lookups will be time-proportional to the number of words in the list, and there will be significant overhead in terms of list management, because each time a new word is entered in the list, you have to be sure it doesn't already exist.

This approach gets a D for ingenuity.

A bright young programmer in your department comes to you at this point and says "Wait! I have a better idea." He explains that if you keep the linked list sorted alphabetically, you can speed lookups because they will occur in time-proportion to the log of the number of entries. List-maintenance overhead is reduced as well, although storage requirements haven't changed.

This represents a significant improvement. Let's give it a C+ (or maybe even a C++) for effort.

At this point, a consultant walks in the door and offers to solve the problem for you in such a way that up to 40,000 words can be stored in your exception dictionary and lookups are instantaneous, with zero table maintenance. You say to him "Thank you, but that's clearly impossible. Don't let the doorknob hit you in the butt on the way out." He goes straight to your competitor, implements the solution, and eventually the competitor puts you out of business. You end up face-down in the gutter, next to an empty bottle of Ripple.

How did the consultant do it? First of all, since you are only concerned with whether a given word has an entry (true) in the dictionary or not (false), you're really looking for a binary (Boolean) answer to a question; hence your 5K dictionary can really store 40K lookups (assuming 8-bit bytes, of course). The dictionary needs to be implemented as a bit table.

To implement a direct lookup of words, we resort to the following heuristic. To store a word in the dictionary, we submit the word string to a hash function, which in turn converts the word from a string to a number in the range of zero to 5K-minus-one. We then index into the bit table at the offset thus obtained, and store the word by flipping the bit "on." (A zero bit means the word doesn't exist in the table.) To look up a word and see if it exists in the exception dictionary, we simple hash the word and do a direct lookup. If the entry in the table at that lookup is true, the word exists. If not, it doesn't. Problem solved.

Finally, an A+ solution!

Hash Functions

But we still haven't resolved the question of what a hash function looks like. Earlier we merely said that it could look like whatever it needs to look like. Let's take the exception-dictionary example we just discussed. How many bits' worth of information does a 5-character string really hold? If the string represents an English word, each character can have one of 26 possible values (except that the first character can be upper or lower case; hence 52 possible values). Storing 26 possibilities requires 4.7 bits; 52 possibilities requires 5.7 bits. The average word therefore requires 5.7 + 4 * 4.7 == just under 25 bits of bandwidth. Every 5-character English word can therefore be converted (mapped directly and unambiguously) to a 25-bit number. Which is to say, a number between zero and 33,554,431.

Clearly, if we had 32 million bits (4 megabytes) of storage available, and words could never be longer than five characters, you could convert words directly to binary numbers and use the numbers as offsets into a bit table.

Unfortunately, in the real world, words are not constrained to five characters in length and four megabytes of table storage are not always available. In fact, our example calls for no more than 5 Kbytes (40Kbits) of storage.

Why not take the bottom 15 bits of each word (discarding the rest) and use that as an index into a 40Kbit table? The answer should be obvious. Words often have the same endings. Taking the last 15 bits of 'eating' and 'drinking' would result in both words contending for the same spot in the exception dictionary. Totally unsatisfactory.

The crux of understanding how a hash solution works in this kind of situation is to think long and carefully about the problem. If you think about it, you will realize that the ASCII values in words are not at all randomly chosen. The composition of word strings in English is constrained by spelling rules, which in turn are determined, in part, by constraints on the speakability of syllables (i.e., the geometry of the human voice apparatus). The average English word may consume only 25 bits of bandwidth, but there most certainly are not 32 million different 5-letter words in the English language! The actual number of different 5-letter words you might encounter might only be in the low thousands. Certainly, in a spellchecker context, 5-letter "exception" words (words that are not commonly found in English) would likely be numbered in the low hundreds, if that many.

Careful analysis of the problem space should convince you that what we're really dealing with here is a sparse data set. We will be mapping a few hundred exceptions (or at most, a few thousand) into a 40,000-bit table. All we need is a way to convert words to numbers that map well across the available domain.

Suppose we design a hash function in C as shown in Listing 1 (where ch is a pointer to the word string).

Listing 1: hash()


unsigned int hash(ch) {

   unsigned int hashvalue = 0;

    if (!*ch) return 0; // sanity

   do {
      hashvalue += *ch++;
      hashvalue *= 13; 
   } while (*ch);

  return (hashvalue % TABLESIZE);

This hash function adds the ASCII value of each character in the string, one by one, to a temporary variable. But in between each addition, the variable is multiplied by the magic number 13, which (in binary terms) is equivalent to a left-shift by log(13) bits. (Prove to yourself that this is so.) What's the significance of 13? Nothing. It simply works. Might some other number work better? Yes! That's the magic of hash functions. Often, you can "tune" them to make them work better.

What does "work better" mean? It means you have fewer situations where two different character strings hash to the same numeric value. When two data objects hash to the same value, it's called a hash collision. Collisions are usually undesirable. In our exception-dictionary example, it could mean that a nonsense word maps to the same dictionary location as a perfectly valid word!

Dealing with Collisions

There are various ways of handling collisions. The most common way (not for bit tables, but for tables where actual string information might be stored) is to fork a linked-list node at the point of the collision. Another method is to keep parallel tables, but with different hash functions for each. An "entry" in the dictionary would actually consist of an entry in each table. A lookup would verify that Hash 1 produces a positive result from Table 1 and Hash 2 yields a positive result from Table 2. Prove to yourself that (given suitably designed hash functions) if a collision happens in the first hash table, it's extremely unlikely that a collision also occurs, simultaneously, in the other hash table; therefore, the overall collision rate is the product of two small numbers (the individual failure rates of the hashes).

In some situations, collisions can safely be ignored; the "collider" overwrites the old table entry, and that's that. This can actually be desirable in instances where data entities are expected to regularly go out of scope. (In this case, you have what is commonly known as a "weak" associative array). In the spellchecker example, it's debatable whether collisions are important. No spellchecker is ever perfect. If the odds of a misspelled word hashing to the same spot as a legitimate word are less than, say, one in five thousand, would the user really notice? Would he care?

Hash Tuning

The fascinating thing about hash functions like the one above is that they can be tuned for better collision performance (lower collision rates). What makes this fascinating is the fact that, because the problem is so poorly defined (mathematically), an analytical solution is usually out of the question. Therefore, tuning must be done empirically: try a tweak, measure the result. Try another tweak; measure the result. Repeat until happy.

You might want to write a short program that takes a text stream (a document) as input and maps the "vocabulary" to a hash table, measuring collision rates in the process. Find out how collision rate varies with load factor (table consumption) for a given hash function. Then try changing the function in some way, and see how the collision performance changes.

The example hash function given in Listing 1 is actually a surprisingly good hash function for most purposes. With a driver program (such as HashMule; see further below), you can prove to yourself, empirically, that this modest-looking function works much better (i.e., produces many fewer collisions) than the same function with the number 12 substituted for the number 13. (This is why I called 13 a magic number.) In fact, when I ran a quick test of Listing 1 using the Declaration of Independence as the source text (hashed into a table with room for 1024 words), I found that changing the magic number 13 to 12 caused collisions to more than double.

In general, even numbers produce poor results, and non-prime odd numbers (while better) are not as good as primes.

When writing a hash function, you will always need to constrain the final output to a certain range (in our example, 5K). Be aware that, for tuning purposes, it can matter a great deal what the "modulo" constraint is. Again, it turns out that a prime number here will improve performance. So make your lookup table an odd size! (But don't take my word for it. Write a test program and prove it to yourself.)

A Common Hash Misconception

A common misconception is that hash functions are designed to distribute values randomly over a given range. You should convince yourself that this is not true. After all, if hashing were this easy, every hash function would simply return a random number (converted to integer form and scaled to fit the desired range). The ideal hash function is usually one that distributes keys evenly across a range, with no collisions. Random numbers tend to cause collisions, at a rate equivalent to the hashtable load factor. (That is, when the lookup table gets half full, each new entry into the table has a 50:50 chance of generating a collision.) A good hash function can do much better, because hash functions can be constructed to remap data non-randomly. And in fact, this is exactly what you are trying to achieve. You are trying to map a sparse, non-random data set to non-random locations in a table: locations that spread out evenly and don't overlap. If you know a thing or two about the data before you begin, you can make intelligent decisions about how to craft the hash function.

Consider a list of 500 arbitrarily chosen unique words selected from Webster's dictionary at random. Imagine that you are trying to map these words into a hash table that has enough space for all 500 words, but only enough space. (But you don't necessarily know in advance how many words there are.) Can it be done? Of course. You just need to develop a hash function that maps table positions to the words' alphabetical ranking. If you can analyze the word list in advance, this is a piece of cake. If you don't have advance access to the words, but your hash object is free to reorder table data on the fly, again it's not a hard problem, because you can insert words in alphabetical order and reorder as necessary. Even if you know nothing about the words (except that they are words!), you can easily come up with a hash function that does a better job of mapping them to a table (i.e., with fewer collisions) than mere random dart-throwing.

There's no magic procedure for constructing a good hash function. Each situation is different. What might be a great function for one set of conditions could very well be terrible under another set of conditions. The trick is to understand your data set (and what's unique about it) and understand what it is you are trying to do: map members of the set onto intervals that don't overlap.

Putting Associative Arrays to Work

With a hash function approach in C, we haven't quite achieved the table['string'] lookup ease of other languages, but we've approached it quite closely, because we can instead do:

lookup = table[ hash('myItem') ];

But the greater question, at this point is: How can you put associative arrays to work? One example is well-known: In compilers, symbol tables are usually accessed via a hash function that computes a likely place to begin a serial search. Since symbol-table lookup is a very frequent occurrence in compilers, the performance of the hash function (both in raw execution speed and in collision rate) can have a dramatic effect on overall compiler performance.

But what if you're not a compiler writer? In that case, you might want to consider a possible application that applies broadly across a variety of programming tasks in a variety of languages. It involves 'case' statements.

The Case Against Case Statements

Most high-level languages support a switch construct that allows options to be associated with desired actions. In C:

switch( option ) {

   case OPTION_A : do_something();

   case OPTION_B :
   case OPTION_C : do_something_else();

   // . . . more options processing

   default : do_whatever();

Usually, the cases must refer to hard-coded values. Fall-through occurs by default, which means that if you leave a break statement out (such as with OPTION_B above), execution continues with the next case. The original intent of the switch construct was to keep programmers from having to resort to long chains of if/else actions (while leaving code readable). But hindsight has shown switch/case syntax to be a notably poor syntax design in a number of respects. First of all, it doesn't save any typing (over if/else actions). In fact, switch blocks are usually quite long, because in instances where there are only a couple of cases, programmers tend to collapse everything to a few if/elses. The opportunity for typos is high in long code blocks. Also, the default fall-through behavior of switches is known to be a bad design decision, because it's not the default behavior most programmers are looking for, most of the time. (Some years ago, Sun analyzed its C compiler source code to see how often the default fall-through path was actually used. It turned out the Sun ANSI C compiler's front end had 244 switch statements, averaging seven cases each. Fall-through occurred in only 3% of cases.)

There is also a performance issue, in that the compiler must (because of the possibility of fall-through) evaluate each case in turn, up to the first match. But there's an even bigger problem, architecturally: Switch statements require you to intermix code and static data. This leads to poor maintainability and a host of other ills. It would be better, obviously, to segregate code from static data so that when the data needs to be revised periodically, it can be edited without changing any code.

The answer should be obvious by now: Convert switch blocks to associative arrays. Each case can be used, after all, as a key to find the associated action. (If the associated action is a block of code, then the array need only store a pointer to the appropriate function or macro.) In this way, you can collapse the entire switch block down to one line of code, which executes instantly.

Consider the common situation, in CGI/forms programming, of retrieving a user selection from a drop-down menu and taking action on it. Usually, you have something like this:

var userSelection = element.options[i].value;

switch(userSelection) {

   case 'Kansas' :  // JavaScript allows string cases

    case 'Ohio' : 

// etc.

   default : whatever();

With an associative array, you can separate data from code and reduce all actions to a single expression. In JavaScript:

// build a lookup table as an Object:
var lookupTable = { 
       'Kansas' : do_this,
       'Ohio'   : do_that,
                 // etc.

// execute action based on lookup:
lookupTable[ userSelection ]( );  

An entire series of if/else statements (or a big, long switch statement) is thus collapsed to one expression, which does one lookup, then vectors to an action procedure. Code is segregated from data, making maintenance easier and less likely to introduce bugs. Performance is improved, many lines of code are reduced to one, and readability doesn't suffer a bit. The best of all worlds. (Just don't tell your competition.)

Sample App: HashMule

For this article, I wrote an educational utility for creating, studying, and comparing the collision rates of hash functions. The app, called HashMule, is actually a PDF form incorporating about 150 lines of JavaScript. It is designed to run under Acrobat Reader version 4.0 or 4.05. You can download HashMule from, or by FTP from the Mactech website.

One of the things HashMule allows you to do is enter hash functions, then execute them against text in real time. A "Hash It" button on the form will hash every word of a given text block into a hash table, then report statistics such as table load factor and hash collision rate. By making small changes in the hash function and hitting the "Hash It" button, you can see how the collision rate changes as you change "magic number" values or hash-function logic. The text of the Declaration of Independence is included in the form as a sample text block.

For Further Information

Associative arrays are such a staple of the Perl language (where they are called hashes) that you'll find them discussed in detail in every decent Perl book and online reference.

Few JavaScript references spend adequate time discussing that language's built-in associative array capabilities. David Flanagan's JavaScript: The Definitive Guide (O'Reilly) is one book that does.

An outstanding introduction to the Java 2 platform's Collections Framework can be found at

There are many good books on STL (the Standard Template Library for C++, which has a rich collections library). It's difficult, however, to find good online information on STL maps. One worthwhile entry point for STL info in general, and information on <map> routines in particular, is Silicon Graphics, Inc. also maintains a very detailed online STL reference: see bear in mind that the SGI implementation of STL contains SGI-defined extensions as well as standard C++ templates.

There are (IMHO) really no good books, at this point, and precious few decent online tutorials, on hash techniques. For instructive online examples, you should search the Google search engine using keywords "hash" and "cryptography." (One paper that's worth a careful look is, "The Breaking of CyberPatrol 4," by Eddy L. O. Jansson and Matthew Skala.)

Kas Thomas has been programming in C and assembly on the Mac platform since before Windows existed. By day, he is a Senior Technical Writer for Silverstream Software (a maker of app-server softwar. You can reach him in care of


Community Search:
MacTech Search:

Software Updates via MacUpdate

Macs Fan Control - Monitor and c...
Macs Fan Control allows you to monitor and control almost any aspect of your computer's fans, with support for controlling fan speed, temperature sensors pane, menu-bar icon, and autostart with... Read more
calibre 2.69.0 - Complete e-book library...
Calibre is a complete e-book library manager. Organize your collection, convert your books to multiple formats, and sync with all of your devices. Let Calibre be your multi-tasking digital librarian... Read more
Evernote 6.9.1 - Create searchable notes...
Evernote allows you to easily capture information in any environment using whatever device or platform you find most convenient, and makes this information accessible and searchable at anytime, from... Read more
jAlbum Pro 13.5 - Organize your digital...
jAlbum Pro has all the features you love in jAlbum, but comes with a commercial license. You can create gorgeous custom photo galleries for the Web without writing a line of code! Beginner-friendly... Read more
jAlbum 13.5 - Create custom photo galler...
With jAlbum, you can create gorgeous custom photo galleries for the Web without writing a line of code! Beginner-friendly, with pro results - Simply drag and drop photos into groups, choose a design... Read more
Google Chrome 53.0.2785.143 - Modern and...
Google Chrome is a Web browser by Google, created to be a modern platform for Web pages and applications. It utilizes very fast loading of Web pages and has a V8 engine, which is a custom built... Read more
Chromium 53.0.2785.143 - Fast and stable...
Chromium is an open-source browser project that aims to build a safer, faster, and more stable way for all Internet users to experience the web. Version 53.0.2785.143: [Security Fix] High CVE-2016-... Read more
QuickBooks 2015 R8 - Financi...
Save 20% on QuickBooks Pro for Mac today through this special discount link QuickBooks 2015 helps you manage your business easily and efficiently. Organize your finances all in one place, track... Read more
Sierra Cache Cleaner 11.0.1 - Clear cach...
Sierra Cache Cleaner is an award-winning general purpose tool for macOS X. SCC makes system maintenance simple with an easy point-and-click interface to many macOS X functions. Novice and expert... Read more
Default Folder X 5.0.7 - Enhances Open a...
Default Folder X attaches a toolbar to the right side of the Open and Save dialogs in any OS X-native application. The toolbar gives you fast access to various folders and commands. You just click on... Read more

Pumped BMX 3: Beginner tips and tricks
There’s a whole lot more to Pumped BMX 3 than meets the eye. Your goal is to perform a wide array of sweet flips and tricks, but that’s easier said than done. It takes well practiced timing and coordination, and the game doesn’t really explain that... | Read more »
Cybird’s latest release - BFB Champions...
Launched in the UK in early September, BFB Champions’ newest update is loaded with great new features, and looks set to outshine the original version by taking it out of soft launch and giving it a new lease of life. | Read more »
3 apps to boost your focus
As someone who works from home, my workspace is a minefield of distraction. Cats, tasty snacks, the wind blowing past my window, that cleaning that I suddenly can’t put off any longer. If I let distraction takes its course, I find that soon half... | Read more »
Pumped BMX 3 (Games)
Pumped BMX 3 1.0 Device: iOS Universal Category: Games Price: $3.99, Version: 1.0 (iTunes) Description: The final instalment of the smash hit #1 rated BMX game is here! Following on from the insane success of Pumped BMX 2, Pumped 3... | Read more »
4 games like Burly Men at Sea to inspire...
Burly Men at Sea is out today and it looks a treat. It tells the tale of three Scandinavian fishermen who leave the humdrum of their daily lives to go exploring. It’s a beautiful folksy story that unfurls as you interact with the environment... | Read more »
3 reasons you need to play Kingdom: New...
Developed by a tag team of indie developers - Thomas "Noio" van den Berg and Marco "Licorice" Bancale - Kingdom is a vibrant medieval fantasy adventure that casts players as a king or queen who must expand their empire by exploring the vasts lands... | Read more »
JoyCity have launched a brand new King o...
Great news for all of you Game of Dice fans out there - JoyCity have just released a brand new limited edition pack with a really cool twist. The premise of Game of Dice is fairly straightforward, asking you to roll dice to navigate your way around... | Read more »
Burly Men at Sea (Games)
Burly Men at Sea 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: Burly Men at Sea is a folktale about a trio of large, bearded fishermen who step away from the ordinary to seek adventure. | Read more »
3 tips for catching the gnarliest waves...
Like a wave breaking on the shore, Tidal Rider swept its way onto the App Store charts this week settling firmly in the top 10. It’s a one-touch high score-chaser in which you pull surfing stunts while dodging seagulls and collecting coins. The... | Read more »
The beginner's guide to destroying...
Age of Heroes: Conquest is 5th Planet Games’ all new turn-based multiplayer RPG, full of fantasy exploration, guild building, and treasure hunting. It’s pretty user-friendly as far as these games go, but when you really get down to it, you’ll find... | Read more »

Price Scanner via

CAZE Annouces New Zero 5 Case for Jet Black i...
Hong Kong basd CAZE has announced Zero 5 case for iPhone 7/ 7 Plus, one of the world’s thinnest clear hard cases, measuring just 0.5 millimeters. CAZE has been producing and improving the Zero 5... Read more
Nest Egg Inventory App for iOS Offers Conven...
Campbell, California based Winprogger LLC has announced the release and immediate availability of Nest Egg – Inventory 4.1.22, an important update to their easy-to-use, yet comprehensive inventory... Read more
Factor4, LLC Launches Apple iOS and Android G...
Factor4, LLC, which offers gift and loyalty services to the SMB marketplace, has released free mobile applications that enable merchants to process via all Apple and Android devices. The Apple and... Read more
15-inch Retina MacBook Pros on sale for $200...
B&H Photo has 15″ Retina Apple MacBook Pros on sale for $200 off MSRP. Shipping is free, and B&H charges NY tax only: - 15″ 2.2GHz Retina MacBook Pro: $1799 $200 off MSRP - 15″ 2.5GHz Retina... Read more
Apple refurbished iMacs available for up to $...
Apple has Certified Refurbished 2015 21″ & 27″ iMacs available for up to $350 off MSRP. Apple’s one-year warranty is standard, and shipping is free. The following models are available: - 21″ 3.... Read more
Check Apple prices on any device with the iTr...
MacPrices is proud to offer readers a free iOS app (iPhones, iPads, & iPod touch) and Android app (Google Play and Amazon App Store) called iTracx, which allows you to glance at today’s lowest... Read more
Apple price trackers, updated continuously
Scan our Apple Price Trackers for the latest information on sales, bundles, and availability on systems from Apple’s authorized internet/catalog resellers. We update the trackers continuously: - 15″... Read more
Apple refurbished 2016 13-inch MacBook Airs a...
Apple has Certified Refurbished 2016 13″ MacBook Airs available starting at $849. An Apple one-year warranty is included with each MacBook, and shipping is free: - 2016 13″ 1.6GHz/8GB/128GB MacBook... Read more
1.4GHz Mac mini on sale for $449, save $50
Adorama has the 1.4GHz Mac mini on sale for $50 off MSRP including free shipping plus NY & NJ sales tax only: - 1.4GHz Mac mini (Apple sku# MGEM2LL/A): $449 $50 off MSRP To purchase a mini at... Read more
Apple refurbished 2015 13-inch MacBook Airs a...
Apple has Certified Refurbished 2015 13″ MacBook Airs available starting at $759. An Apple one-year warranty is included with each MacBook, and shipping is free: - 2015 13″ 1.6GHz/4GB/128GB MacBook... Read more

Jobs Board

Systems Architecture Prototyping - *Apple*...
Changing the world is all in a day's work at Apple . If you love innovation, here's your chance to make a career of it. You'll work hard. But the job comes with more Read more
*Apple* Retail - Multiple Positions- Akron,...
Job Description:SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Hardware Design Validation Engineer - *Apple...
Changing the world is all in a day's work at Apple . If you love innovation, here's your chance to make a career of it. You'll work hard. But the job comes with more Read more
Systems Architecture Prototyping - *Apple*...
Changing the world is all in a day's work at Apple . If you love innovation, here's your chance to make a career of it. You'll work hard. But the job comes with more Read more
*Apple* Retail - Multiple Positions- South B...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.