Javascript: Convert string to array of objects? - javascript

Tell me, how can I optimally convert a string like
const data = "1350, 1351, 1390-1391, 1401, 1402 - 1407";
to an array like
const range = [
{
min: 1350,
max: 1350,
},
{
min: 1351,
max: 1351,
},
{
min: 1390,
max: 1391,
},
{
min: 1401,
max: 1401,
},
{
min: 1402,
max: 1407,
},
];
?
In other words, you need to create an array of number ranges using a string in which these numbers ranges are explicitly specified.
The most obvious of the possible algorithms is:
1) split the string using a delimiter,
2) the resulting parts are cleaned of spaces using the command trim
3) check whether the part is a number
4) if not, then split the part using the delimiter -
5) the parts obtained are cleaned of spaces using the command trim,
6) check that the amount of component eq 2 and it's a number
But is it possible to make it more optimal, more beautiful, more effective?

You can use .split() and .map():
const data = "1350, 1351, 1390-1391, 1401, 1402 - 1407";
const range = data.split(",").map(s => {
let [min, max = min] = s.split("-");
return {min: Number(min), max: Number(max)}
});
console.log(range);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Try something like this:
const data = "1350, 1351, 1390-1391, 1401, 1402 - 1407"
const result = data
.split(/\s*,\s*/)
.map(pair => {
const [min, max = min] = pair
.split(/\s*-\s*/)
.map(Number)
return {
min,
max
}
})
console.log(result)

You can use split method in combination with reduce method.
The reduce() method applies a function against an accumulator and each
element in the array (from left to right) to reduce it to a single
value.
Also, use + operator in order to force result to Number.
const data = "1350, 1351, 1390-1391, 1401, 1402 - 1407";
const array = data.split(', ').reduce(function(arr, elem){
var [min, max] = elem.split('-');
arr.push({
min : + min,
max: + (max || min)
});
return arr;
},[]);
console.log(array);

I think the simple and much understandable way would be to loop through the values and check if they have a range value (with hyphen) and create the object accordingly for the range array.
const data = "1350, 1351, 1390-1391, 1401, 1402 - 1407";
var range = [];
data.split(',').forEach((val)=>{
var obj = {};
if(val.indexOf('-') === -1 ){
obj.min = val;
obj.max = val;
} else {
obj.min = val.split('-')[0].trim();
obj.max = val.split('-')[1].trim();
}
range.push(obj);
});
console.log(range);

This code will help you.
const data = "1350, 1351, 1390-1391, 1401, 1402 - 1407";
var arr = data.split(',');
const range = [];
for(var i=0; i< arr.length; i++){
var b = arr[i].split('-');
if(!b[1])b[1]=b[0];
var obj = new Object();
obj.min = parseInt(b[0]);
obj.max = parseInt(b[1]);
range.push(obj);
}
console.log(range);

Related

create array of object from array of strings

I am trying to solve one issue in my code, so if anyone can help me here?
I have some values added below, So i have one array of string values, which has mac addresses and min & max which is constant values. I am trying to map over macValue and trying to create array of object as given sample below, but unfortunately getting some error there. If anyone can help me out here.
please check here i am trying to dynamically add property inside map.
let macValue = ["MO-CK-DR-01","02","03"]
let min = true
let max = true
// code i have tried
var print = macValue.map((item, i) => {
(item['macAddress'] = item), (item.minimum = min), (item.maximum = max);
return item;
});
trying to create array of object like this
[
{
macAddress: value, //01
mimimum: min,
maximum: max,
},
{
macvalue: value, // 02
mimimum: min,
maximum: max,
},
]
but didn't work and getting this error
As simple as:
let macValue = ["MO-CK-DR-01","02","03"]
let min = true
let max = true
const obj = macValue.map((value) => ({
macvalue: value,
minimum: min,
maximum: max,
}))
let macValue = ['MO-CK-DR-01', '02', '03'];
let min = true;
let max = true;
const result = macValue.map((value) => ({
macValue: value,
minimum: min,
maximum: max
}));
console.log(result);
let macValue = ['MO-CK-DR-01', '02', '03'];
let min = true;
let max = true;
const output = macValue.map(value => ({
macValue: value,
minimum: min,
maximum: max
}));
console.log(output);
As you mentioned, the properties are dynamic, I have used string properties. This should work -
let macValue = ['MO-CK-DR-01', '02', '03'];
let min = true;
let max = true;
const result = macValue.map((value) => ({
'macAddress': value,
'minimum': min,
'maximum': max
}));
console.log(result);

How to convert string to array with ranges JavaScript

Consider the following string: 7, 20, 22, 30–32, 33, 36–40, 46
I developed some code that will automatically parse said string into an array with the given ranges as follows.
Note: A typical use-case for this would be - to search for selected pages within a pdf with 100's of pages
var number_string = "7, 20, 22, 30–32, 33, 36–40, 46".toString().replace(/–/gi, '-').replace(/ /gi, '').split(',');
var new_arr = [];
$.each(number_string, function(index, value) {
if (value.match(/-/gi)) {
var range_arr = value.split('-');
var sub_arr = range(range_arr[0], range_arr[1]);
$.each(sub_arr, function(sub_index, sub_value) {
new_arr.push(parseInt(sub_value, 10));
});
} else {
new_arr.push(parseInt(value, 10));
}
});
console.log(new_arr);
function range(lowEnd, highEnd) {
var arr = [],
c = highEnd - lowEnd + 1;
while (c--) {
arr[c] = highEnd--
}
return arr;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Was there a more streamlined non jQuery method that could have been leveraged here that is also, simple, light weight and easy to read? Please no ES6 stuff as that is Greek to me.
Note: The ToInt function is just a function that returns a valid number or 0.
The jQuery.map() method acts like a flat map (returned sub arrays are flattend). In the map's callback function, use String.search() to check if there's a dash. If not convert to number with the + operator and return. If there's a dash, split, use a for loop to convert the min and max to an array, and return the array.
function convert(str) {
var arr = jQuery.map(str.split(', '), function(s) {
if(s.search('–') === -1) return +s;
var minmax = s.split('–');
var range = [];
for(var i = +minmax[0]; i <= +minmax[1]; i++) range.push(i);
return range;
});
return arr;
}
var number_string = "7, 20, 22, 30–32, 33, 36–40, 46";
var result = convert(number_string);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Using ESNext I would use Array.flatMap() instead of jQuery.map(), with String.inclues() to detect the dash, and Array.from() to generate the sub array.
const convert = (str) =>
str.split(', ')
.flatMap(s => {
if(!s.includes('–')) return +s;
const [min, max] = s.split('–');
return Array.from({ length: max - min + 1 }, (_, n) => n + +min);
});
var number_string = "7, 20, 22, 30–32, 33, 36–40, 46";
var result = convert(number_string, '–');
console.log(result);
I'd use .reduce. First split the initial string by commas. If the string being iterated over doesn't have -, then just push the number to the accumulator; otherwise, split by - to get a low and high number, then use a for loop to push all numbers from low to high to the accumulator:
const ToInt = Number;
const numArr = "7, 20, 22, 30–32, 33, 36–40, 46".split(', ');
const result = numArr.reduce((a, str) => {
if (!str.includes('–')) {
a.push(ToInt(str));
return a;
}
const [low, high] = str.split('–');
for (let i = Number(low); i <= high; i++) {
a.push(i);
}
return a;
}, []);
console.log(result);
If for some reason you don't want to use ES6, you can transform it to ES5 with Babel:
"use strict";
function _slicedToArray(arr, i) {
return (
_arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest()
);
}
function _nonIterableRest() {
throw new TypeError("Invalid attempt to destructure non-iterable instance");
}
function _iterableToArrayLimit(arr, i) {
var _arr = [];
var _n = true;
var _d = false;
var _e = undefined;
try {
for (
var _i = arr[Symbol.iterator](), _s;
!(_n = (_s = _i.next()).done);
_n = true
) {
_arr.push(_s.value);
if (i && _arr.length === i) break;
}
} catch (err) {
_d = true;
_e = err;
} finally {
try {
if (!_n && _i["return"] != null) _i["return"]();
} finally {
if (_d) throw _e;
}
}
return _arr;
}
function _arrayWithHoles(arr) {
if (Array.isArray(arr)) return arr;
}
var ToInt = Number;
var numArr = "7, 20, 22, 30–32, 33, 36–40, 46".split(", ");
var result = numArr.reduce(function(a, str) {
if (str.indexOf("–") === -1) {
a.push(ToInt(str));
return a;
}
var _str$split = str.split("–"),
_str$split2 = _slicedToArray(_str$split, 2),
low = _str$split2[0],
high = _str$split2[1];
for (var i = Number(low); i <= high; i++) {
a.push(i);
}
return a;
}, []);
console.log(result);
(but the ES6 version is more concise and probably a lot easier to read and understand)
I have my own implementation for this purpose
parseStringRange accepts strings like '1,2,3' and '1,2,3-5,6,7', also removes invalid chars (not numbers or , or -) and return one array with all numbers.
the function also returns the numbers ordered and removes duplicates, the user also can input unordered numbers even in range, '1-5' and '5-1' will return same output.
const parseStringRange = (range = '') =>
`${range}`
?.replace(/[^0-9,-]/g, '') //remove invalid chars
?.split(',') //convert 1,2 to [1, 2]
?.flatMap(s => { //convert 1-3 to [1,2,3]
if (!s.includes('-')) return [s]
const [min, max] = s.split('-').map(e => Number(e))
if (min > max) var i = -1
else var i = 1
const r = []
for (let p = min; p != max; p += i)
r.push(p)
r.push(max)
return r;
})
?.map(e => Number(e)) //convert all string numbers to number
?.reduce((t, e, i, a) => {
if (!t)
t = [... new Set(a)]
return t
}, null) //remove duplicates
?.sort((a, b) => a - b) //sort numbers, smallest first

find min and max value using reduce es2015

If I have array of object like this
[{min:5,max:10,id:1}, {min:50,max:3,id:2}, {min:1,max:40,id:3}]
How to find min and max using reduce? I know I can use generic loop and compare but I would like to explore reduce in es2015
You can use reduce like this to get the min and max numbers from each object in the array.
const arr = [{min:5,max:10,id:1}, {min:50,max:3,id:2}, {min:1,max:40,id:3}]
console.log(
arr.reduce((acc, x) => {
acc.min = Math.min(acc.min, x.min)
acc.max = Math.max(acc.max, x.max)
return acc
}, { min: Infinity, max: -Infinity })
)
// as Bergi suggested, we could just return a new Object literal
// from the reduction
console.log(
arr.reduce((acc, x) => ({
min: Math.min(acc.min, x.min),
max: Math.max(acc.max, x.max)
}), { min: Infinity, max: -Infinity })
)
Assuming that you want, for the minimum, to get the id of the item with the lowed min value, then this will do it.
const items = [{min:5,max:10,id:1}, {min:50,max:3,id:2}, {min:1,max:40,id:3}];
// Reduce to find the item with the lowest min
const min = items.reduce((res, item) => {
// No result yet, so the item must be the lowest seen
if (!res) return item;
// Use the lowest of the current lowest and the current item
return item.min < res.min ? item : res;
}, undefined).id;
const arr = [{min:5,max:10,id:1}, {min:50,max:3,id:2}, {min:1,max:40,id:3}];
const min = arr.reduce((m, o) => m < o.min? m: o.min, +Infinity),
max = arr.reduce((M, o) => M > o.max? M: o.max, -Infinity);
console.log("Min:", min);
console.log("Max:", max);
Explanation of min:
const min = arr.reduce((m, o) => { // for each object o in the array arr
return m < o.min? // if o.min is bigger than the minimum m
m: // then the minimum is still m
o.min; // otherwise, the new minimum is o.min
}, +Infinity); // pass in +Ifinity as the minimum (the initial value of m so whatever is arr[0].min is it will be smaller than m). You can pass in arr[0].min if you want instead of +Infinity

Between query result from json array using lodash

I have json array look like this
[
{"hoteldetail":{"hotelid":"00007111","hotelname":"hjghghg","minrate":"500"},
{"hoteldetail"{"hotelid":"00007111","hotelname":"hjghghg","minrate":"1200"},
{"hoteldetail":{"hotelid":"00007111","hotelname":"hjghghg","minrate":"7000"},
{"hoteldetail":{"hotelid":"00007111","hotelname":"hjghghg","minrate":"8000"}
]
From this i want to fetch the items with in a range of minrate
Eg: if the minrate range is (500,7500) it will returns the items from the json array that contains only the minrate with in the above range
So how can i get the output using lodash?
The straightforward implementation is
_.filter(arr, item => _.inRange(item.hoteldetail.minrate, 500, 7501))
which works exactly as it reads: filter the array for item whose property hoteldetail.minrate is within a specified range. However, newer lodash has a very nice function called _.iteratee which allows you to provide a filter shorthand, for example:
_.filter(arr, 'minrate in range 500, 7500')
Here is the implementation
_.iteratee = _.wrap(_.iteratee, function(callback, func) {
var p = /minrate in range (\d+), (\d+)/g.exec(func);
return !p ? callback(func) : function(object) {
return object.hoteldetail.minrate >= p[1] && object.hoteldetail.minrate <= p[2];
};
});
You can use this iteratee just like writing English _.filter(arr, 'minrate in range 100, 200'), _.filter(arr, 'minrate in range 5000, 6000'), etc. You can even go so far as to generalize minrate in the following manner:
_.iteratee = _.wrap(_.iteratee, function(callback, func) {
var p = /(minrate|number\ of\ rooms) in range (\d+), (\d+)/g.exec(func);
return !p ? callback(func) : function(object) {
var prop = object.hoteldetail[p[1]];
return prop >= p[2] && prop <= p[3];
};
});
And use it as _.filter(arr, 'number of rooms in range 1, 5')
Doc: https://lodash.com/docs#iteratee
var _ = require('lodash'); //lodash 4.5
var hotels = [
{"hoteldetail":{"hotelid":"00007111","hotelname":"hjghghg","minrate":"500"}},
{"hoteldetail":{"hotelid":"00007111","hotelname":"hjghghg","minrate":"1200"}},
{"hoteldetail":{"hotelid":"00007111","hotelname":"hjghghg","minrate":"7000"}},
{"hoteldetail":{"hotelid":"00007111","hotelname":"hjghghg","minrate":"8000"}}
]
var filteredItems = _.filter(hotels, function(hotel){
return _.inRange(hotel.hoteldetail.mitrate, 500, 7500);
});

Compare properties of objects stored in array

I have an JavaScript array of this format:
var dimensions = [
{dim: 590, token:'...'},
{dim: 800, token:'.....'},
{dim: 2500, token:'........'}
];
Data in dimensions array is populated dynamically i.e. I' don't know whether it is gonna be zero, one or 50 objects with dim and token properties.
What I need is to pick token from object that have largest value of dim, and smallest value of dim. Anyone have a clue how do I do that?
I suggest to use Array.prototype.reduce(). It returns an object with the min and max object of the array.
var dimensions = [
{ dim: 590, token: '...' },
{ dim: 800, token: '.....' },
{ dim: 2500, token: '........' }
],
result = dimensions.reduce(function (r, a) {
r.min = r.min || a;
r.max = r.max || a;
return {
min: r.min.dim < a.dim ? r.min : a,
max: r.max.dim > a.dim ? r.max : a
};
}, {});
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
var dimensions = [
{dim: 590, token:'...'},
{dim: 800, token:'.....'},
{dim: 2500, token:'........'}
];
// Sort the function in ascending order and pick the first and the last element.
var minmax = dimensions.sort(function(a,b){
return a.dim - b.dim;
}).filter(function(el, i){
return i==0 || i==dimensions.length-1;
});
// minmax will have two values, first will be minimum and second will be the largest.
console.log("Smallest: "+minmax[0].token);
console.log("Largest: "+minmax[1].token);
Use sort function to sort the array first and then pick first and last element from array.
dimensions.sort(function(a,b)
{
return a.dim - b.dim
});
var tokenOfSmallest = dimensions[0].token;
var tokenOfLargest = dimensions[dimensions.length - 1].token;
Although most answers provided here are correct, they are not the optimal solutions for your problem (Except Nina Scholz).
Sorting the array via Array.sort() takes a Big-O complexity of O(n*log(n)), but your problem could certainly be solved with a faster, O(n) algorithm.
var dimensions = [
{dim: 590, token:'...'},
{dim: 800, token:'.....'},
{dim: 2500, token:'........'}
];
function getTokenForLargestDim(array)
{
if(array.length === 0) { throw new Error('Empty array'); }
var maxDim = Number.NEGATIVE_INFINITY;
var maxIndex = -1;
for(var i=0; i < array.length; i++) {
var lastDim = maxDim;
if(dimensions[i].dim > maxDim) { maxDim = dimensions[i].dim; maxIndex = i;}
}
return array[maxIndex].token;
}
getTokenForLargestDim(dimensions);
sort the dimensions array first in ascending order and then get smallest and largest token value
dimensions.sort(function(a, b) {
return parseInt(a.dim) - parseInt(b.dim);
});
var smallest = dimensions[ 0 ].token;
var largest = dimensions[ dimensions.length - 1 ].token;
You can reduce your array to find max/min:
var result = dimensions.reduce(function(r, item) {
r.max = !r.max || r.max.dim < item.dim ? item : r.max;
r.min = !r.min || r.min.dim > item.dim ? item : r.min;
return r;
}, {});
console.log(result.max.token);
console.log(result.min.token);

Categories