views:

67

answers:

3

I need to store the user preferences in a cookie.

  • I have three multiple select drop downs & date.
  • User is allowed to select all the values in dropdowns.

If I store all the unique (8 characters) values in a cookie, then it will get overloaded. I need a mechanism to do some mapping so that minimal value is stored in cookie.

My requirement matches this question, but only difference is that I have large data set (100 items per select column).

+3  A: 

Two possibilities:

A) Make your values numeric and powers of 2 (1,2,4,8,16,etc) and store a single value in the cookie as a bitmap. (Or in the server-side code, map the distinct values to powers of 2.)

B) Store the values in the cookie as a delimited list.

Updated: 6:40PM

Seeing that you have the possibility of a large number of selections, neither of my original solutions is going to work. To deal with that large an amount of data, I think you're going to need to create a "session id" of some sort, save the actual settings in a database or other persistent storage, and store the session id in the cookie.

(You'll of course want to make the cookie only persist for the duration of the browser session and delete the stored settings after you can be reasonably certain the browser session has ended -- perhaps a week or so.)

ThatBlairGuy
+1 for the bitwise mask suggestion, although you may encounter problems for lists larger than roughly 31 or 53 items, because of the [size limits of the Number type](http://stackoverflow.com/questions/307179/what-is-javascripts-max-int-whats-the-highest-integer-value-a-number-can-go-to).
Niels van der Rest
Yeah, and now that I see the comment about the possibility of 300 values, neither of my original possibilities looks particularly viable.
ThatBlairGuy
+1  A: 

You can store the indexes of the selected items. For example, if the user has selected item 1 and 3 from list A, item 4 from list B and the first 10 items of list C, you'd get something like this:

A[0,2],B[3],C[0-9]

You'd have to write some simple parsing code to read out the values though.

In the worst case scenario, when the user has selected all the odd or even items, you'll need about 150 characters for a list containing a total of 100 items. If the user has selected all 100 items, you'll only need A[0-99].

Niels van der Rest
Hmm, that's a good idea, wish I thought about it :-)
R. Hill
jaan
Yes, instead of the indexes, you'll have to store the actual value of the option. In that case, you can also use other characters as values, such as the alphabet. Then you can have more single-character values and you'll need less characters in your cookie.
Niels van der Rest
+2  A: 

That's a good question. Given your requirements, I don't see much choices left on how to proceed. As ThatBlairGuy suggested, a bit map seems to be the way to go. Your 300 choices translate to 300 bits. Now I personally would stick to use only 6 bits per byte, to make a quick and easy translation to base64, for storage purpose. 300 / 6 = 50 characters for the values coming from the drop-down.

The value of any preference has to be hardcoded for good though, you can't remove or add any in the middle: Any new preference will have to be added at the end of the bit map, or use a bit that is no longer used somewhere in the map.

Edit: Given the comments re. bit map, I will flesh out what I had in mind for the implementation. Assuming a bit, each corresponding to a off-on switch of a particular option (an entry in the drop-box):

this.bitmap = [];
this.customBase64code="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+-";
...
// index=index of bit within bit map, on=state of the bit
this.setOption=function(index,on) {
    var islot = Math.floor(index / 6);
    var ibit = index % 6;
    if ( this.bitmap[islot] === undefined ) {
        while ( this.bitmap.length <= islot ) {
            this.bitmap.push(0);
        }
    }
    if (on) {
        this.bitmap[islot] |= (1 << ibit);
    }
    else {
        this.bitmap[islot] &= ~(1 << ibit);
    }
};
this.getOption=function(index) {
    var islot = Math.floor(index / 6);
    if ( this.bitmap[islot] === undefined ) {
        return 0;
        }
    return this.bitmap[islot] & (1 << (index % 6));
};
this.getStringFromOptions=function() {
    var bitmap64 = [];
    var encoder64 = customBase64code.split('');
    var n = this.bitmap.length;
    for ( var i = 0; i < n; i++ ) {
        bitmap64.push(encoder64[this.bitmap[i]]);
    }
    return bitmap64.join('');
};
this.getOptionsFromString=function(s) {
    var bitmap64 = s.split('');
    var decoder64 = this.customBase64code;
    var n = bitmap64.length;
    for ( var i = 0; i < n; i++ ) {
        this.bitmap.push(decoder64.indexOf(bitmap64[i]));
    }
};

Disclaimer: I didn't test any of the above.

R. Hill
+1 for the base64. That squeezes a lot more bits out of a single character than the hexadecimal I was thinking of.
ThatBlairGuy
In the absence of a 300-bit integer type, mapping back to the original values would still be cumbersome in an all-JavaScript solution, but not insurmountable.
ThatBlairGuy
Niels van der Rest
Added a suggested implementation
R. Hill