Javascript Object: find a key/value when in range - javascript

i have a Javascript object like this one:
pItems = {
single : {
...
plz: {
"1000": 12,
"2000-2500" : 40
"3000": 30
}
...
}
}
i get a value from an inputfield e.g. "2300" and now i need the value for this "2300" from the object. Because 2300 is in the range of the plz-key "2000-2500" the value i should get back is "40".
i have no clue atm how i could find the right value, if i am looking up something in key "ranges".
thank you for any advice, help with that.

You can iterate over the keys, split them, if possible and perform a check. If in range, then return the item and leave the loop.
function getItem(value) {
var item;
Object.keys(object.plz).some(function (k) {
var part = k.split('-');
if (+value >= part[0] && +value <= (part[1] || part[0])) {
item = object.plz[k];
return true;
}
});
return item;
}
var object = { plz: { "1000": 12, "2000-2500": 40, "3000": 30 } };
console.log(getItem('1000'));
console.log(getItem('2300'));

var pItems = {
single : {
plz: {
"1000": 12,
"2000-2500" : 40,
"3000": 30
}
}
};
var val =2300 ;
$.each(pItems.single.plz, function(k,v) {
var min = parseInt(k.split('-')[0]);
var max = parseInt(k.split('-')[1]);
if(isNaN(max) ){
if(min == val){
console.log(v);
return;
}
}else if(val>=min || val <= max){
console.log(v);
return;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>

Wraped as function:
function getValue(search) {
for( var range in pItems.plz ) {
var split = range.split("-");
if( search >= parseInt(split[0]) && search <= parseInt(split[1] || split[0]) )
return pItems.plz[range];
}
}
Call:
console.log(getValue(1000)); // 12
console.log(getValue(2300)); // 40
console.log(getValue(3000)); // 30
console.log(getValue(5000)); // undefined

Related

jquery.seat-charts.js Uncaught TypeError: Cannot read property 'status' of undefined

I am using Jquery Seat chart for a ticket reservation system. Everything is working fine but when i am calling a function which returns already booked seats, the status of seats is not changing to 'already booked'.
I am getting 'jquery.seat-charts.js Uncaught TypeError: Cannot read property 'status' of undefined' error.
here is my code:
function getBookedSeats() {
jQuery(document).ready(function ($) {
$.ajax({
type : 'get',
url : 'bookings/getSelectedSeats',
data : 'show_id=<?php echo $show_id ?>',
success : function(response) {
response1 = JSON.parse(response);
$.each(response1.bookings, function (index, booking) {
sc.status(booking.seat_id, 'unavailable');
});
}
});
});
}
and the error iam getting is in jquery.seat-chart.js on line 486.
jquery.seat-chart.js
(function($) {
//'use strict';
$.fn.seatCharts = function (setup) {
//if there's seatCharts object associated with the current element, return it
if (this.data('seatCharts')) {
return this.data('seatCharts');
}
var fn = this,
seats = {},
seatIds = [],
legend,
settings = {
animate : false, //requires jQuery UI
naming : {
top : true,
left : true,
getId : function(character, row, column) {
return row + '_' + column;
},
getLabel : function (character, row, column) {
return column;
}
},
legend : {
node : null,
items : []
},
click : function() {
if (this.status() == 'available') {
return 'selected';
} else if (this.status() == 'selected') {
return 'available';
} else {
return this.style();
}
},
focus : function() {
if (this.status() == 'available') {
return 'focused';
} else {
return this.style();
}
},
blur : function() {
return this.status();
},
seats : {}
},
//seat will be basically a seat object which we'll when generating the map
seat = (function(seatCharts, seatChartsSettings) {
return function (setup) {
var fn = this;
fn.settings = $.extend({
status : 'available', //available, unavailable, selected
style : 'available',
//make sure there's an empty hash if user doesn't pass anything
data : seatChartsSettings.seats[setup.character] || {}
//anything goes here?
}, setup);
fn.settings.$node = $('<div></div>');
fn.settings.$node
.attr({
id : fn.settings.id,
role : 'checkbox',
'aria-checked' : false,
focusable : true,
tabIndex : -1 //manual focus
})
.text(fn.settings.label)
.addClass(['seatCharts-seat', 'seatCharts-cell', 'available'].concat(
//let's merge custom user defined classes with standard JSC ones
fn.settings.classes,
typeof seatChartsSettings.seats[fn.settings.character] == "undefined" ?
[] : seatChartsSettings.seats[fn.settings.character].classes
).join(' '));
//basically a wrapper function
fn.data = function() {
return fn.settings.data;
};
fn.char = function() {
return fn.settings.character;
};
fn.node = function() {
return fn.settings.$node;
};
/*
* Can either set or return status depending on arguments.
*
* If there's no argument, it will return the current style.
*
* If you pass an argument, it will update seat's style
*/
fn.style = function() {
return arguments.length == 1 ?
(function(newStyle) {
var oldStyle = fn.settings.style;
//if nothing changes, do nothing
if (newStyle == oldStyle) {
return oldStyle;
}
//focused is a special style which is not associated with status
fn.settings.status = newStyle != 'focused' ? newStyle : fn.settings.status;
fn.settings.$node
.attr('aria-checked', newStyle == 'selected');
//if user wants to animate status changes, let him do this
seatChartsSettings.animate ?
fn.settings.$node.switchClass(oldStyle, newStyle, 200) :
fn.settings.$node.removeClass(oldStyle).addClass(newStyle);
return fn.settings.style = newStyle;
})(arguments[0]) : fn.settings.style;
};
//either set or retrieve
fn.status = function() {
return fn.settings.status = arguments.length == 1 ?
fn.style(arguments[0]) : fn.settings.status;
};
//using immediate function to convienietly get shortcut variables
(function(seatSettings, character, seat) {
//attach event handlers
$.each(['click', 'focus', 'blur'], function(index, callback) {
//we want to be able to call the functions for each seat object
fn[callback] = function() {
if (callback == 'focus') {
//if there's already a focused element, we have to remove focus from it first
if (seatCharts.attr('aria-activedescendant') !== undefined) {
seats[seatCharts.attr('aria-activedescendant')].blur();
}
seatCharts.attr('aria-activedescendant', seat.settings.id);
seat.node().focus();
}
/*
* User can pass his own callback function, so we have to first check if it exists
* and if not, use our default callback.
*
* Each callback function is executed in the current seat context.
*/
return fn.style(typeof seatSettings[character][callback] === 'function' ?
seatSettings[character][callback].apply(seat) : seatChartsSettings[callback].apply(seat));
};
});
//the below will become seatSettings, character, seat thanks to the immediate function
})(seatChartsSettings.seats, fn.settings.character, fn);
fn.node()
//the first three mouse events are simple
.on('click', fn.click)
.on('mouseenter', fn.focus)
.on('mouseleave', fn.blur)
//keydown requires quite a lot of logic, because we have to know where to move the focus
.on('keydown', (function(seat, $seat) {
return function (e) {
var $newSeat;
//everything depends on the pressed key
switch (e.which) {
//spacebar will just trigger the same event mouse click does
case 32:
e.preventDefault();
seat.click();
break;
//UP & DOWN
case 40:
case 38:
e.preventDefault();
/*
* This is a recursive, immediate function which searches for the first "focusable" row.
*
* We're using immediate function because we want a convenient access to some DOM elements
* We're using recursion because sometimes we may hit an empty space rather than a seat.
*
*/
$newSeat = (function findAvailable($rows, $seats, $currentRow) {
var $newRow;
//let's determine which row should we move to
if (!$rows.index($currentRow) && e.which == 38) {
//if this is the first row and user has pressed up arrow, move to the last row
$newRow = $rows.last();
} else if ($rows.index($currentRow) == $rows.length-1 && e.which == 40) {
//if this is the last row and user has pressed down arrow, move to the first row
$newRow = $rows.first();
} else {
//using eq to get an element at the desired index position
$newRow = $rows.eq(
//if up arrow, then decrement the index, if down increment it
$rows.index($currentRow) + (e.which == 38 ? (-1) : (+1))
);
}
//now that we know the row, let's get the seat using the current column position
$newSeat = $newRow.find('.seatCharts-seat,.seatCharts-space').eq($seats.index($seat));
//if the seat we found is a space, keep looking further
return $newSeat.hasClass('seatCharts-space') ?
findAvailable($rows, $seats, $newRow) : $newSeat;
})($seat
//get a reference to the parent container and then select all rows but the header
.parents('.seatCharts-container')
.find('.seatCharts-row:not(.seatCharts-header)'),
$seat
//get a reference to the parent row and then find all seat cells (both seats & spaces)
.parents('.seatCharts-row:first')
.find('.seatCharts-seat,.seatCharts-space'),
//get a reference to the current row
$seat.parents('.seatCharts-row:not(.seatCharts-header)')
);
//we couldn't determine the new seat, so we better give up
if (!$newSeat.length) {
return;
}
//remove focus from the old seat and put it on the new one
seat.blur();
seats[$newSeat.attr('id')].focus();
$newSeat.focus();
//update our "aria" reference with the new seat id
seatCharts.attr('aria-activedescendant', $newSeat.attr('id'));
break;
//LEFT & RIGHT
case 37:
case 39:
e.preventDefault();
/*
* The logic here is slightly different from the one for up/down arrows.
* User will be able to browse the whole map using just left/right arrow, because
* it will move to the next row when we reach the right/left-most seat.
*/
$newSeat = (function($seats) {
if (!$seats.index($seat) && e.which == 37) {
//user has pressed left arrow and we're currently on the left-most seat
return $seats.last();
} else if ($seats.index($seat) == $seats.length -1 && e.which == 39) {
//user has pressed right arrow and we're currently on the right-most seat
return $seats.first();
} else {
//simply move one seat left or right depending on the key
return $seats.eq($seats.index($seat) + (e.which == 37 ? (-1) : (+1)));
}
})($seat
.parents('.seatCharts-container:first')
.find('.seatCharts-seat:not(.seatCharts-space)'));
if (!$newSeat.length) {
return;
}
//handle focus
seat.blur();
seats[$newSeat.attr('id')].focus();
$newSeat.focus();
//update our "aria" reference with the new seat id
seatCharts.attr('aria-activedescendant', $newSeat.attr('id'));
break;
default:
break;
}
};
})(fn, fn.node()));
//.appendTo(seatCharts.find('.' + row));
}
})(fn, settings);
fn.addClass('seatCharts-container');
//true -> deep copy!
$.extend(true, settings, setup);
//Generate default row ids unless user passed his own
settings.naming.rows = settings.naming.rows || (function(length) {
var rows = [];
for (var i = 1; i <= length; i++) {
rows.push(i);
}
return rows;
})(settings.map.length);
//Generate default column ids unless user passed his own
settings.naming.columns = settings.naming.columns || (function(length) {
var columns = [];
for (var i = 1; i <= length; i++) {
columns.push(i);
}
return columns;
})(settings.map[0].split('').length);
if (settings.naming.top) {
var $headerRow = $('<div></div>')
.addClass('seatCharts-row seatCharts-header');
if (settings.naming.left) {
$headerRow.append($('<div></div>').addClass('seatCharts-cell'));
}
$.each(settings.naming.columns, function(index, value) {
$headerRow.append(
$('<div></div>')
.addClass('seatCharts-cell')
.text(value)
);
});
}
fn.append($headerRow);
//do this for each map row
$.each(settings.map, function(row, characters) {
var $row = $('<div></div>').addClass('seatCharts-row');
if (settings.naming.left) {
$row.append(
$('<div></div>')
.addClass('seatCharts-cell seatCharts-space')
.text(settings.naming.rows[row])
);
}
/*
* Do this for each seat (letter)
*
* Now users will be able to pass custom ID and label which overwrite the one that seat would be assigned by getId and
* getLabel
*
* New format is like this:
* a[ID,label]a[ID]aaaaa
*
* So you can overwrite the ID or label (or both) even for just one seat.
* Basically ID should be first, so if you want to overwrite just label write it as follows:
* a[,LABEL]
*
* Allowed characters in IDs areL 0-9, a-z, A-Z, _
* Allowed characters in labels are: 0-9, a-z, A-Z, _, ' ' (space)
*
*/
$.each(characters.match(/[a-z_]{1}(\[[0-9a-z_]{0,}(,[0-9a-z_ ]+)?\])?/gi), function (column, characterParams) {
var matches = characterParams.match(/([a-z_]{1})(\[([0-9a-z_ ,]+)\])?/i),
//no matter if user specifies [] params, the character should be in the second element
character = matches[1],
//check if user has passed some additional params to override id or label
params = typeof matches[3] !== 'undefined' ? matches[3].split(',') : [],
//id param should be first
overrideId = params.length ? params[0] : null,
//label param should be second
overrideLabel = params.length === 2 ? params[1] : null;
$row.append(character != '_' ?
//if the character is not an underscore (empty space)
(function(naming) {
//so users don't have to specify empty objects
settings.seats[character] = character in settings.seats ? settings.seats[character] : {};
var id = overrideId ? overrideId : naming.getId(character, naming.rows[row], naming.columns[column]);
seats[id] = new seat({
id : id,
label : overrideLabel ?
overrideLabel : naming.getLabel(character, naming.rows[row], naming.columns[column]),
row : row,
column : column,
character : character
});
seatIds.push(id);
return seats[id].node();
})(settings.naming) :
//this is just an empty space (_)
$('<div></div>').addClass('seatCharts-cell seatCharts-space')
);
});
fn.append($row);
});
//if there're any legend items to be rendered
settings.legend.items.length ? (function(legend) {
//either use user-defined container or create our own and insert it right after the seat chart div
var $container = (legend.node || $('<div></div>').insertAfter(fn))
.addClass('seatCharts-legend');
var $ul = $('<div class="row"></div>')
.addClass('seatCharts-legendList')
.appendTo($container);
$.each(legend.items, function(index, item) {
$ul.append(
$('<div class="col-md-2 col-xs-2"></div>')
.addClass('seatCharts-legendItem')
.append(
$('<div></div>')
//merge user defined classes with our standard ones
.addClass(['seatCharts-seat', 'seatCharts-cell', item[1]].concat(
settings.classes,
typeof settings.seats[item[0]] == "undefined" ? [] : settings.seats[item[0]].classes).join(' ')
)
)
.append(
$('<span></span>')
.addClass('seatCharts-legendDescription')
.text(item[2])
)
);
});
return $container;
})(settings.legend) : null;
fn.attr({
tabIndex : 0
});
//when container's focused, move focus to the first seat
fn.focus(function() {
if (fn.attr('aria-activedescendant')) {
seats[fn.attr('aria-activedescendant')].blur();
}
fn.find('.seatCharts-seat:not(.seatCharts-space):first').focus();
seats[seatIds[0]].focus();
});
//public methods of seatCharts
fn.data('seatCharts', {
seats : seats,
seatIds : seatIds,
//set for one, set for many, get for one
status: function() {
var fn = this;
return arguments.length == 1 ? fn.seats[arguments[0]].status() : (function(seatsIds, newStatus) {
return typeof seatsIds == 'string' ? fn.seats[seatsIds].status(newStatus) : (function() {
$.each(seatsIds, function(index, seatId) {
fn.seats[seatId].status(newStatus);
});
})();
})(arguments[0], arguments[1]);
},
each : function(callback) {
var fn = this;
for (var seatId in fn.seats) {
if (false === callback.call(fn.seats[seatId], seatId)) {
return seatId;//return last checked
}
}
return true;
},
node : function() {
var fn = this;
//basically create a CSS query to get all seats by their DOM ids
return $('#' + fn.seatIds.join(',#'));
},
find : function(query) {//D, a.available, unavailable
var fn = this;
var seatSet = fn.set();
//is RegExp
return query instanceof RegExp ?
(function () {
fn.each(function (id) {
if (id.match(query)) {
seatSet.push(id, this);
}
});
return seatSet;
})() :
(query.length == 1 ?
(function (character) {
//user searches just for a particual character
fn.each(function () {
if (this.char() == character) {
seatSet.push(this.settings.id, this);
}
});
return seatSet;
})(query) :
(function () {
//user runs a more sophisticated query, so let's see if there's a dot
return query.indexOf('.') > -1 ?
(function () {
//there's a dot which separates character and the status
var parts = query.split('.');
fn.each(function (seatId) {
if (this.char() == parts[0] && this.status() == parts[1]) {
seatSet.push(this.settings.id, this);
}
});
return seatSet;
})() :
(function () {
fn.each(function () {
if (this.status() == query) {
seatSet.push(this.settings.id, this);
}
});
return seatSet;
})();
})()
);
},
set : function set() {//inherits some methods
var fn = this;
return {
seats : [],
seatIds : [],
length : 0,
status : function() {
var args = arguments,
that = this;
//if there's just one seat in the set and user didn't pass any params, return current status
return this.length == 1 && args.length == 0 ? this.seats[0].status() : (function() {
//otherwise call status function for each of the seats in the set
$.each(that.seats, function() {
this.status.apply(this, args);
});
})();
},
node : function() {
return fn.node.call(this);
},
each : function() {
return fn.each.call(this, arguments[0]);
},
get : function() {
return fn.get.call(this, arguments[0]);
},
find : function() {
return fn.find.call(this, arguments[0]);
},
set : function() {
return set.call(fn);
},
push : function(id, seat) {
this.seats.push(seat);
this.seatIds.push(id);
++this.length;
}
};
},
//get one object or a set of objects
get : function(seatsIds) {
var fn = this;
return typeof seatsIds == 'string' ?
fn.seats[seatsIds] : (function() {
var seatSet = fn.set();
$.each(seatsIds, function(index, seatId) {
if (typeof fn.seats[seatId] === 'object') {
seatSet.push(seatId, fn.seats[seatId]);
}
});
return seatSet;
})();
}
});
return fn.data('seatCharts');
}
})(jQuery);
since the sc.status(par1,par2) expects first par1 in format of 'Row_Col' and second par2 as unavailable. i had to convert the seat number in par1 format by:
$.each(response1.bookings, function (index, booking) {
var seat_n = convertSeat(booking.seat_id);
sc.get(seat_n).status('unavailable');
});
convertSeat()
function convertSeat(seat_number) {
if(seat_number <= 29){
var seat_node = 'A_'+seat_number;
return seat_node;
}
else if(seat_number <= 58){
var seat = seat_number - 29;
var seat_node = 'B_'+seat;
return seat_node;
}
else if(seat_number <= 87){
var seat = seat_number - 58;
var seat_node = 'C_'+seat;
return seat_node;
}
else if(seat_number <= 116){
var seat = seat_number - 87;
var seat_node = 'D_'+seat;
return seat_node;
}
else if(seat_number <= 145){
var seat = seat_number - 116;
var seat_node = 'E_'+seat;
return seat_node;
}
else if(seat_number <= 174){
var seat = seat_number - 145;
var seat_node = 'F_'+seat;
return seat_node;
}
else if(seat_number <= 203){
var seat = seat_number - 174;
var seat_node = 'G_'+seat;
return seat_node;
}
else if(seat_number <= 232){
var seat = seat_number - 203;
var seat_node = 'H_'+seat;
return seat_node;
}
else if(seat_number <= 261){
var seat = seat_number - 232;
var seat_node = 'I_'+seat;
return seat_node;
}
else if(seat_number <= 290){
var seat = seat_number - 261;
var seat_node = 'J_'+seat;
return seat_node;
}
else if(seat_number <= 319){
var seat = seat_number - 290;
var seat_node = 'K_'+seat;
return seat_node;
}
else if(seat_number <= 348){
var seat = seat_number - 319;
var seat_node = 'L_'+seat;
return seat_node;
}
else if(seat_number <= 377){
var seat = seat_number - 348;
var seat_node = 'M_'+seat;
return seat_node;
}
else if(seat_number <= 406){
var seat = seat_number - 377;
var seat_node = 'N_'+seat;
return seat_node;
}
else if(seat_number <= 435){
var seat = seat_number - 406;
var seat_node = 'O_'+seat;
return seat_node;
}
else if(seat_number <= 464){
var seat = seat_number - 435;
var seat_node = 'P_'+seat;
return seat_node;
}
else if(seat_number <= 493){
var seat = seat_number - 464;
var seat_node = 'Q_'+seat;
return seat_node;
}
else if(seat_number <= 522){
var seat = seat_number - 493;
var seat_node = 'R_'+seat;
return seat_node;
}
else if(seat_number <= 551){
var seat = seat_number - 522;
var seat_node = 'S_'+seat;
return seat_node;
}
}

Previous or next element in array based on string "direction"

I'm trying to make function that will return next or previous item in array, based on parameter "direction".
For example I have array = ['ferrari', 'bmw', 'merc', 'bugatti'] and I want my my function to return 'bugatti' IF currentPointer = 'ferrari' and direction = 'left'
nextPrev(array,direction,currentPointer)
In php we have function next() which moves the internal pointer ... but I don't know how to do it in javascript ...
Try Something like this.
Using the numerical locations of the array and conditionally cycle through:
var array = ['ferrari', 'bmw', 'merc', 'bugatti'];
var returnedElement = nextPrev(array, "left", "ferrari");
// Show Returned Value (Console)
console.log(returnedElement);
function nextPrev(array, direction, currentPointer) {
var arraySize = array.length - 1;
var currentIndex = array.indexOf(currentPointer);
if (direction === "left") {
// Decrease array by one
if (currentIndex == 0) {
// Return Previous (Max Array)
return array[arraySize]
} else {
return array[currentIndex - 1]
}
} else if (direction === "right") {
// Increase array by one
if (currentIndex == arraySize) {
// Go to zero position
return array[0]
} else {
return array[currentIndex + 1]
}
} else {
console.log("Use either 'left' or 'right'");
}
}
The basic idea would be:
function nextPrev(array, direction, currentPointer) {
var index = array.indexOf(currentPointer);
if (direction=="left") {
return array[index == 0 ? array.length-1 : index-1];
} else if (direction=="right") {
return array[index == array.length-1 ? 0 : index+1];
} else {
// default action or throw error
}
}
You can reorganize this a bit:
function nextPrev(array, direction, currentPointer) {
var index = array.indexOf(currentPointer);
var len = array.length;
if (direction=="left") {
index--;
} else if (direction=="right") {
index++
} else {
// default action or throw error
}
return array[(index + len) % len];
}
You might want to add a check that array.indexOf returns a valid index (in case currentPointer contains something not in array).
You can write something like this:
function makeDirectionalIterator(array){
var currIndex = 0;
return {
nextPrev: function(direction){
if(direction === 'left') {
return currIndex < array.length-1 ?
{value: array[++currIndex], done: false} :
{done: true};
}
else {
return currIndex > 0 ?
{value: array[--currIndex], done: false} :
{done: true};
}
},
current: function() {
return { value: array[currIndex] };
}
}
}
Then you can use it like the following
var itr = makeDirectionalIterator(array);
itr.current().value;
itr.nextPrev('left').value;
itr.nextPrev('left').done;

how to get specific last decimal float value

var fNum = parseFloat("32.23.45"); results in 32.23 but I need the string from last decimal point: 23.45
For example, the following strings should return the following values:
"12.234.43.234" -> 43.234,
"345.234.32.34" -> 32.34 and
"234.34.34.234w" -> 34.34
A fairly direct solution:
function toFloat(s) {
return parseFloat(s.match(/\d+(\.|$)/g).slice(-2).join('.'));
}
For example:
toFloat("32.23.45") // 23.45
toFloat("12.234.43.234") // 43.234
toFloat("345.234.32.34") // 32.34
toFloat("234.34.34.234w") // 34.34
Update: Here's an alternative version which will more effectively handle strings with non-digits mixed in.
function toFloat(s) {
return parseFloat(s.match(/.*(\.|^)(\d+\.\d+)(\.|$)/)[2]);
}
The following will do exactly what you would like (I'm presuming that the last one should return 34.234, not 34.24).
alert (convText("12.234.43.234"));
alert (convText("345.234.32.34"));
alert (convText("234.34.34.234w"));
function convText(text) {
var offset = text.length - 1;
var finished = false;
var result = '';
var nbrDecimals = 0;
while(!finished && offset > -1) {
if(!isNaN(text[offset]) || text[offset] === '.') {
if(text[offset] === '.') {
nbrDecimals++;
}
if(nbrDecimals > 1) {
finished = true;
} else {
result = text[offset] + result;
}
}
offset--;
}
return result;
}

Getting nested obj value

Given the following obj:
var inputMapping = {
nonNestedItem: "someItem here",
sections: {
general: "Some general section information"
}
};
I'm writing a function to get that data by passing in a string "nonNestedItem" or in the nested case "sections.general". I'm having to use an eval and I was wondering if there was maybe a better way to do this.
Here is what I have so far and it works okay. But improve!
function getNode(name) {
var n = name.split(".");
if (n.length === 1) {
n = name[0];
} else {
var isValid = true,
evalStr = 'inputMapping';
for (var i=0;i<n.length;i++) {
evalStr += '["'+ n[i] +'"]';
if (eval(evalStr) === undefined) {
isValid = false;
break;
}
}
if (isValid) {
// Do something like return the value
}
}
}
Linky to Jsbin
You can use Array.prototype.reduce function like this
var accessString = "sections.general";
console.log(accessString.split(".").reduce(function(previous, current) {
return previous[current];
}, inputMapping));
Output
Some general section information
If your environment doesn't support reduce, you can use this recursive version
function getNestedItem(currentObject, listOfKeys) {
if (listOfKeys.length === 0 || !currentObject) {
return currentObject;
}
return getNestedItem(currentObject[listOfKeys[0]], listOfKeys.slice(1));
}
console.log(getNestedItem(inputMapping, "sections.general".split(".")));
You don't need to use eval() here. You can just use [] to get values from an object. Use a temp object to hold the current value, then update it each time you need the next key.
function getNode(mapping, name) {
var n = name.split(".");
if (n.length === 1) {
return mapping[name];
} else {
var tmp = mapping;
for (var i = 0; i < n.length; i++) {
tmp = tmp[n[i]];
}
return tmp;
}
}

Getting the value from key in a dictionary that is nearest to a given number using JavaScript

I have a dictionary (keys are integers, values are float). I would now ask the dictionary for the value of the key that is > than the given number but < than the next greater key.
Example:
dict = {100: 0.0035, 150: 0.0024, 200: 0.0019}.
i give 122, it should give me 0.0035
i give 333, it should give me 0.0019
i give 200, it should give me 0.0024
Thanks!
This is a perfect use-case for a binary tree. The topic is a little broad for a stack overflow answer, but here goes anyway.
function addValueToNode(tree, nodeidx, value) {
var left = 2*nodeidx + 1;
var right = 2*nodeidx + 2;
if(value > tree[nodeidx]) {
if(!tree[right])
tree[right] = value;
else
addValueToNode(tree, right, value);
} else {
if(!tree[left])
tree[left] = value;
else
addValueToNode(tree, left, value);
}
}
function addValueToTree(tree, value) {
if(tree.length == 0)
tree.push(value)
else
addValueToNode(tree, 0, value);
}
function addValuesToTree(tree, values) {
for(var i = 0; i < values.length; i++)
addValueToTree(tree, values[i]);
}
function addDictionaryToTree(tree, dict) {
var values = [];
for(var key in dict) {
values.push(key);
}
values.sort();
addValuesToTree(tree, values);
}
function findClosestValue(tree, nodeidx, value) {
var left = 2*nodeidx + 1;
var right = 2*nodeidx + 2;
if(value > tree[nodeidx]) {
if(!tree[right] || tree[right] == value)
return tree[nodeidx];
else
return findClosestValue(tree, right, value);
} else {
if(!tree[left])
return tree[nodeidx];
else
return findClosestValue(tree, left, value);
}
}
var tree = [];
var dict = {100: 0.0035, 150: 0.0024, 200: 0.0019};
addDictionaryToTree(tree, dict);
var closest = findClosestValue(tree, 0, 175);
var dictValue = dict[closest];
alert( closest + " : " + dictValue);
Working example (tested under Firefox 3.6):
<html>
<head>
<script type="text/javascript" src="jquery-1.3.2.min.js"></script>
<script type="text/javascript">
var dict = {100: 0.0035, 150: 0.0024, 200: 0.0019};
function r(aNum) {
var result;
for (var key in dict) {
var dist = key - aNum
if ((dist < 0 && dist < result) || result === undefined) {
result = key;
}
}
return dict[result];
}
$(document).ready(function() {
$('li').each(function() {
var id = $(this).attr('id').replace('n', '')
$(this).html(id + ": " + r(id));
});
});
</script>
</head>
<body>
<ul>
<li id="n122"></li>
<li id="n333"></li>
<li id="n200"></li>
</ul>
</body>
</html>
var value = 122;
var min = null;
var minkey = null;
for ( var key : dict ) {
if (min==null || abs(value-key)<min) {
min=abs(value-key);
minkey = key;
}
}
return dict[minkey]
You can try this. Sorry if smth, i have no chance to test it.
The following function matchs your requirements:
function getNumber(dict, value) {
var key, found;
for (key in dict) {
if (value - key > 0) {
found = key;
}
}
return dict[found];
}
var dict = {100: 0.0035, 150: 0.0024, 200: 0.0019};
// Firebug assertions
console.assert(getNumber(dict, 122) == 0.0035);
console.assert(getNumber(dict, 333) == 0.0019);
console.assert(getNumber(dict, 200) == 0.0024);
Binary search, using a modified (stable) algorithm that searches for the least element meeting the comparison criteria.
If your dictionary is not huge, you could try to cycle from, for example, (122-1). If it's undefined, subtract 1 and try again, until you find something :)

Categories