0ab5447b6e091c22232b33b0c85bc6f2

I have to get the last key of an associativ array...
I searched a special function, but I don't find it.

ps: I'm so sorry for my english, if you want to refactor it ;)

1
2
3
4
5
6
7
8
9
10
11
//creation and affectation
myArray= new Array();
myArray[2]='something';
myArray[7]='somthingelse';
myArray[99]='thelastone';

//my current function
function getLastKey(var a){
    for(var key in a){}
    return key;
}

Refactorings

No refactoring yet !

1945ab4cdb87eaf5a5c906fa884c29f1

Scott Robinson

December 6, 2007, December 06, 2007 13:06, permalink

3 ratings. Login to rate!

x = new Array();
x[2] = 'something';
x[7] = 'somethingelse';
x[99] = 'thelastone';

return x[x.length - 1];

0ab5447b6e091c22232b33b0c85bc6f2

jojolapine

December 6, 2007, December 06, 2007 16:26, permalink

No rating. Login to rate!

Hello,
I think your solution will not function.
Your example will return the string "thelastone", or I want to get the number 99....

Avatar

Emmett

December 7, 2007, December 07, 2007 01:42, permalink

2 ratings. Login to rate!

Scott's solution is correct, but if you want it as a function...

1
2
3
function lastKey(arr){
  return arr[arr.length - 1];
}
Avatar

Sedril

December 7, 2007, December 07, 2007 07:21, permalink

1 rating. Login to rate!

He want the key, so you where not to far... Here 99.

1
2
3
function getLastKey(arr){
  return (arr.length - 1);
}
0ab5447b6e091c22232b33b0c85bc6f2

jojolapine

December 7, 2007, December 07, 2007 09:37, permalink

No rating. Login to rate!

Hy!!
Your two solutionswill not work... (for me)
Your exemple Emmett will return in my exemple: 'thelastone'
and you Sedril, your solution will return the number 2...
Or I want to get the number 99...
I'm sorry...

Avatar

Sedril

December 7, 2007, December 07, 2007 11:04, permalink

1 rating. Login to rate!

Test it, it works fine !

Avatar

V

December 7, 2007, December 07, 2007 11:24, permalink

No rating. Login to rate!

You are all reading the code, but not reading the text! He clearly says he wants an associative array, not that it exists in JS, but the closest thing would be the "last" property of an object, hence his use of for..in.
The problem then is: I really am not sure all implementations of javascript will keep and return properties of an object in the same order, always.

Avatar

Andre Steenveld

December 10, 2007, December 10, 2007 12:33, permalink

No rating. Login to rate!

V the for...in loop displays quite random behavior and you can't say anything about the "key" you have except that it is a member of the object you are looping through. I have written ( a quick and dirty ) Map class currently i am still writing some unit tests for it but any comments are quite welcome.

Edit Some bug fixes:
- Get elements by index
- Make it work
- added unit tests

The Map and some additional stuff

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
Object.extend = function( target, source ){
    var key = "";
    for( key in source ){
        target[ key ] = source[ key ]; }

    return target;
};

var Map = ( function(){

    function getArrayIndex( arr, obj ){
        for( var i = 0; i < arr.length; i++ ){
            if( arr[ i ] === obj ){
                break;
        }    }

        return i;
    }

    // Our little container class, this will be the wrapper for everything we put
    // into the Map object. We want to inform the dev about the key index and that
    // sort of stuff but not let em mess with it...
    var MapItem = function( key, value, items, keys ){
        Object.extend( this, {
            getKey:        function(){ return key; },
            getIndex:      function(){ return getArrayIndex( items, this ); },
            getIndexOfKey: function(){ return getArrayIndex( keys, key ); },

            getValue: function(){ return value; },
            setValue: function( newValue ){
                value = newValue;
                return this;
            }
        });
    };

    // Key map a little class wich can help us keeping the order for the keys...
    var KeyIndexer = {
        create: function( ){
            // IE stupidface won't let me inheret from Array so we need a create method
            // and just rudly overwrite the methods.
            return Object.extend( [ ], {
                // Override the push function so can "push" another key into our collection
                // but istead of just sticking it to the end we will do a little sort first
                // and find the right position. ( Is overriding push() the right course of
                // action here? )
                push: function( key ){
                    for( var i = 0; i < this.length; i++ ){
                        if( /*jsl:ignore*/
                            ( key === this[ i ] )                     // In case we have deplicates
                            || ( i === ( this.length - 1 ) )          // In case we are at the last element
                            || ( key > this[ i ] && key < this[ i ] ) // If we have a real fitting key
                        ){  /*jsl:end*/
                            break;
                        }
                    }

                    this.splice( i, 0, key );

                    return i;
                }
            });
        }
    };

    // The constructor for the Map class here is where the real magic happens.
    return function(){
        // Create some private collections so we can sort all kind of stuff
        var keyArray = KeyIndexer.create( ),
            indexArray = [ ],
            mapObject = { };

        Object.extend( this, {

            add: function( key, value ){
                // Create our item
                var item = new MapItem( key, value, indexArray, keyArray );

                // Add the correct properties and stuff to the collection
                keyArray.push( key.toString() );
                indexArray.push( item );
                mapObject[ key.toString() ] = item;
                return item;
            },
            remove: function( key ){
                var item = this.get( key );

                if( item === null ){ return false; }

                keyArray.splice( item.getIndexOfKey(), 1 );
                indexArray.splice( item.getIndex(), 1 );
                delete mapObject[ key ];

                return true;
            },

            // Some default getters and settings no real magic. If for some
            // reason or another the thing we are looking for is not
            // available we will return null.
            get: function( key ){
                if( typeof key === "string" ){
                    return mapObject[ key ] || null;

                } else if( typeof key === "number" ){
                    return indexArray[ key ] || null;

                }

                return null;
            },

            first: function( ){ return indexArray[ 0 ] || null; },
            last: function( ){ return indexArray[ indexArray.length - 1 ] || null; },

            firstByKey: function( ){ return mapObject[ keyArray[ 0 ] ] || null; },
            lastByKey: function( ){ return mapObject[ keyArray[ keyArray.length - 1 ] ] || null; },

            length: function(){ return keyArray.length; },
            toString: function(){ return "[ Map Object ]"; }
        });
    };
})();

Bunch of (sloppy) unit tests

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
<html>
    <head>
        <script type="text/javascript" src="./map.js"></script>
        <script type="text/javascript">

function createHtmlElement ( elementObj ){
    elementObj = Object.extend({
        tagName: "!--",
        attributes: { },
        innerHTML: " ",
        singelTag: false
    }, elementObj);

    var htmlString = [ "<", elementObj.tagName ];

    for( var attribute in elementObj.attributes ){
        htmlString.push( " " + attribute );
        htmlString.push( attribute.substr(0, 2) === "on" ?
            "=\"(" + elementObj.attributes[attribute].toString() + ")( event );\" " :
            "=\"" + elementObj.attributes[attribute] + "\" " );
    }

    htmlString.push( elementObj.singelTag ? "/>" : ">" );
    htmlString.push( elementObj.innerHTML ); // <-- can be pretty large sometimes...
    htmlString.push( !elementObj.singleTag ? "</" + elementObj.tagName + ">" : "" );

    return htmlString.join("");
}

function observe(element, name, handler) {
    if (element.addEventListener) {
        element.addEventListener(name, handler, false);
    } else {
        element.attachEvent("on" + name, handler);
    }
}

var uniqeId = ( function(){
    var lastId = null;

    return function( ){
        var newId = "uid_" + ( new Date( ) ).getTime( ).toString( 36 );

        lastId = ( newId === lastId ? uniqeId( ) : newId );

        return lastId;
    };
})( );

var myKeys = [ uniqeId(), uniqeId(), uniqeId(), uniqeId() ],
    myValues = [
        { toString: function( ){ return "[ 00 " + myKeys[ 0 ] + " ]"; } },
        { toString: function( ){ return "[ 01 " + myKeys[ 1 ] + " ]"; } },
        { toString: function( ){ return "[ 02 " + myKeys[ 2 ] + " ]"; } },
        { toString: function( ){ return "[ 03 " + myKeys[ 3 ] + " ]"; } }
    ],
    myMap = new Map( );

var results = [
    [ "Creating a new map", myMap instanceof Map ],
    [ "Because it is empty the first should be null", !myMap.first() && !myMap.last() && !myMap.firstByKey() && !myMap.lastByKey() ],
    [ "The map is empty so the length should be 0 aswell", myMap.length() === 0 ]    
];

// Lets continue testing and add a item
myMap.add( myKeys[ 0 ], myValues[ 0 ] );

results.push( [ "The length should now be 1", myMap.length() === 1 ] );
results.push( [ "We should get stuff out now...", !!myMap.first() && !!myMap.last() && !!myMap.firstByKey() && !!myMap.lastByKey() ] );
results.push( [ "Even when look by key.", !!myMap.get( myKeys[ 0 ] ) ] );
results.push( [ "Getting by index.", !!myMap.get( 0 ) ] );

// Add a bunch of objects to the map and test the item object
myMap.add( myKeys[ 2 ], myValues[ 2 ] );
myMap.add( myKeys[ 3 ], myValues[ 3 ] );

results.push( [ "Added some items te map should be 3 big now.", myMap.length() === 3 ] );

results.push( [ "When getting the first item form the map.", myMap.first().getKey() === myKeys[ 0 ] ] );
results.push( [ "The value should be the same aswell", myMap.first().getValue() === myValues[ 0 ] ] );
results.push( [ "The index ofcourse should be 0.", myMap.first().getIndex() === 0 ] );
results.push( [ "And it is the smallest key...", myMap.first().getIndexOfKey() === 0 ] );

results.push( [ "When getting the last item form the map.", myMap.last().getKey() === myKeys[ 3 ] ] );
results.push( [ "The value should be the same aswell", myMap.last().getValue() === myValues[ 3 ] ] );
results.push( [ "The index ofcourse should be 2.", myMap.last().getIndex() === 2 ] );
results.push( [ "And it is the biggest key...", myMap.last().getIndexOfKey() === 2 ] );

results.push( [ "Getting by index and key.", myMap.get( 1 ) === myMap.get( myKeys[ 2 ] ) ] );

// Now for some key magic
myMap.add( myKeys[ 1 ], myValues[ 1 ] );

results.push( [ "The last one pushed..", myMap.last().getValue() === myValues[ 1 ] ] );
results.push( [ "A key wich should fit between 0 and 2", myMap.last().getIndexOfKey() === 1 ] );

observe( window, "load", function(){
    var output = [];

    for( var i = 0; i < results.length; i++ ){
        output.push( "<tr>"
            + "<td>" + results[ i ][ 0 ] + "</td>"
            + "<td style='background-color: " + ( results[ i ][ 1 ] ? "#0F6" : "#F06" ) + "; border: black solid 1px;'>"
              + ( results[ i ][ 1 ] ? "Passed" : "Failed" )
            + "</td></tr>" );            
    }

    document.body.innerHTML = createHtmlElement({
        tagName: "table",
        attributes: {
            style: "border: black solid 1px;"
        },
        innerHTML: createHtmlElement({
            tagName: "tbody",
            innerHTML: output.join( "" )
        })
    });
});

        </script>
    </head>

    <body>
        <!-- stuff goes here -->
    </body>
</html>
Ff71c4381eaf3816bffda6c6fe53d33e

Kalpesh

December 17, 2007, December 17, 2007 18:51, permalink

1 rating. Login to rate!

You can make an array of array to achieve this thing.
Please look at the code below.

Hope that helps.

1
2
var d = [[1,"hello"], [2,"world"], [99,"test"]]; 
alert(d[d.length-1][0]);

Your refactoring





Format Copy from initial code

or Cancel