Suppose I have 3 strings: s1 = "ab", s2 = "cd", s3 = "ef".
The goal is to create another string by combining s1, s2, and s3. The catch is that the user can decide the positions of those 3 strings. So, for instance:
s1 - position 3;
s2 - position 2;
s3 - position 1
Result:
efcdab.
My question is, what is the best way to solve this problem? My solution was to create 3 objects that will each hold the string position and value as properties, add the objects into and array and then sort the array using the position property of each object, but I just have the feeling that there is a better solution.
Thanks in advance!
Just giving it a try where you strPos is the user defined object for ordering the strings
var s1 = 'ab';
var s2 = 'cd';
var s3 = 'ef';
var strs = {s1:s1,s2:s2,s3:s3};
var strPos = {1:'s1',2:'s3',3:'s2'};
var fin = '';
for(var i=1;i<=3;i++){
fin += strs[strPos[i]];
}
console.log(fin);
#Five from your comments the answer can be changed to follow your object structure as below
var definedOrderedList = [{
value: 'ab',
position: 2
}, {
value: 'cd',
position: 1
}, {
value: 'ef',
position: 3
}];
var strArr = [];
for (var o in definedOrderedList) {
strArr[definedOrderedList[o].position] = definedOrderedList[o].value;
}
var finalString = strArr.join('');
console.log(finalString);
If your strings and positions are given as an array of {value, position} objects, you can use Array.reduce to order and concatenate them to an ordered string in linear time:
let strings = [
{value: "ab", position: 3},
{value: "cd", position: 2},
{value: "ef", position: 1}
];
let string = strings.reduce((sorted, next) => {
sorted[next.position - 1] = next.value;
return sorted;
}, []).join("");
console.log(string); // "efcdab"
You can use two objects. One that has string and values, lets say values like
{
s1: 'String1',
s2: 'String2',
s3: 'String3'
}
and one lets say position object like
{
p1: 'store user entry for position1',
p2: 'store user entry for position2',
p3: 'store user entry for position3'
}
and access first object like this values[position['p1']] add to values[position['p2']] and so on
Based on how you described your object structure, looks like you will have an array like this(chosen one possible random ordering):
var arr = [ { value: "ab", position: 2 }, { value: "cd", position: 1 }, { value: "ef", position: 3 } ];
Then you can sort the array based on the position and then concatenate the strings.
var arr = [ { value: "ab", position: 2 }, { value: "cd", position: 1 }, { value: "ef", position: 3 } ];
arr.sort((a,b) => a.position - b.position);
var ans="";
for(var i=0;i<arr.length;i++) {
ans += arr[i].value;
}
console.log(ans);
I'm not sure how you are having them pick the order, but with this all you have to do is fill in the options for them to choose and it does the rest of the work. This can be made prettier by a lot, but that is up to you and how you take user interaction.
var selections = ["ab", "cd", "ef"];
var str = "";
while(selections.length){
var choice = prompt("Type part of the string from below that you want to add first:\n " + " " + selections);
var index = selections.indexOf(choice);
if(index !== -1){
str += choice;
selections.splice(index, 1);
}
}
alert("You typed: " + str);
Related
In NodeJS I have a string like this
"Package=Package&Qty=1&Price=123?Package=Package Two&Qty=3&Price=702?Package=Package Three&Qty=1&Price=199?Package=Package One&Qty=4&Price=852?"
In the string you can see there are multiple Package, Qty and Price. Now I want to send email for each Qty and Package. So if you see Package Two it has Qty 3. So in that case there it will send 3 emails with Package and Price. So basically it will send email for each Qty with corresponding Package and Price.
So for now I have my code like this
var string = "Package=Package&Qty=1&Price=123?Package=Package Two&Qty=3&Price=702?Package=Package Three&Qty=1&Price=199?Package=Package One&Qty=4&Price=852?";
var packArr = string.split('?');
var PackageName;
var PackagePrice;
for (var i = 0; i < packArr.length; i++) {
if( packArr[i].length > 0 ) {
let packageQty = packArr[i].split('&');
for (var j = 0; j < packageQty.length; j++) {
if( packageQty[j].match(/Package=/i) ) {
PackageName = packageQty[j].replace(/Package=/g,'');
console.log(PackageName);
}
if( packageQty[j].match(/Price=/i) ) {
PackagePrice = packageQty[j].replace(/Price=/g,'');
console.log(PackagePrice);
}
if (packageQty[j].match(/Qty=/i)) {
var ret = packageQty[j].replace(/Qty=/g,'');
var Pck = Number(ret);
for (var k = 1; k <= Pck; k++) {
console.log(k);
console.log('Package Name ' + PackageName);
console.log('Package Price ' + PackagePrice);
//send email with Package Name, Package Price
if( k == Pck ) {
break;
}
}
}
}
}
}
The above code actually not working properly. It is not getting the Package and Price properly for each loop. So can someone tell me how to do this in a easy way? Any help and suggestions will be really appreciable.
Here's a much cleaner way using querystring package
const string = "Package=Package&Qty=1&Price=123?Package=Package Two&Qty=3&Price=702?Package=Package Three&Qty=1&Price=199?Package=Package One&Qty=4&Price=852?";
const qs = require('querystring');
// We split the string into multiple valid query strings.
// We strip the empty item due to the '?' at the end using .filter(Boolean)
const items = string.split('?').filter(Boolean);
// We loop through each group
for(const query of items) {
// Parse the query string of each group
const { Package, Qty, Price } = qs.parse(query);
for(let i = 0; i < Number(Qty); i++) {
// We send the email here <Qty> times.
console.log('Package Name ' + Package);
console.log('Package Price ' + Price);
}
}
I don't know how you feel about libraries, but Ramda (disclaimer: I'm one of the authors) is well-suited to data-transformations. And this screams for some straightforward data transformation.
I might use it to write a conversion function that changes your initial data into something like:
[
{Package: "Package", Price: 123, Qty: 1},
{Package: "Package Two", Price: 702, Qty: 3},
{Package: "Package Three", Price: 199, Qty: 1},
{Package: "Package One", Price: 852, Qty: 4}
]
This new format should then be easy to work with.
Here is a implementation that does this:
const {pipe, split, filter, map, fromPairs, evolve} = R;
const str = "Package=Package&Qty=1&Price=123?Package=Package Two&Qty=3&Price=702?Package=Package Three&Qty=1&Price=199?Package=Package One&Qty=4&Price=852?";
const convertToObjects = pipe(
split('?'),
filter(Boolean),
map(split('&')),
map(map(split('='))),
map(fromPairs),
map(evolve({Price: Number, Qty: Number}))
);
console.log(convertToObjects(str))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"></script>
map, split, and filter should be obvious.
fromPairs turns [['a', 1], ['b', 2]] into {a: 1, b: 2}.
evolve takes a specification mapping property names to transformation functions, and transforms an object by applying those functions to the relevant properties, keeping all other properties intact. Here we use it with the JS Number function to convert {Package: 'Foo', Qty: '2', Price: '456'} into {Package: 'Foo', Qty: 2, Price: 456}.
and pipe creates a pipeline of functions in which the output of one function becomes the input to the next. Values supplied to the resulting function are sent to the first one and the result of the last one is returned.
Extending #Marcos-casagrande example here without external dependency using plain javascript
const string = "Package=Package&Qty=1&Price=123?Package=Package Two&Qty=3&Price=702?Package=Package Three&Qty=1&Price=199?Package=Package One&Qty=4&Price=852?";
// We split the string into multiple valid query strings.
// We strip the empty item due to the '?' at the end using .filter(Boolean)
const items = string.split('?').filter(Boolean);
// We loop through each group
items.map(query => {
// Parse the query string of each group
const {
Package,
Qty,
Price
} = query.split('&').reduce((acc, cur) => {
let arr = cur.split('=');
return {
...acc,
[arr[0]]: arr[1]
};
}, {});
for (let i = 0; i < Number(Qty); i++) {
// We send the email here <Qty> times.
console.log('Package Name ' + Package);
console.log('Package Price ' + Price);
}
})
Another way using only regexes and a few array methods, not requiring nested loops
var input = "Package=Package&Qty=1&Price=123?Package=Package Two&Qty=3&Price=702?Package=Package Three&Qty=1&Price=199?Package=Package One&Qty=4&Price=852?"
var results = input
.split('?')
.map(s => /^Package=(.*?)&Qty=(.*?)&Price=(.*?)$/.exec(s))
.filter(s => s)
.map(s => ({
package: s[1],
qty: parseFloat(s[2]),
price: parseFloat(s[3])
}))
console.log(JSON.stringify(results, null, 4))
Here is a pure JS alternative, please take a look.
function extract(name, string) {
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
var regexS = "[\\?&]" + name + "=([^&#]*)";
var regex = new RegExp(regexS);
var results = regex.exec(string);
return results == null ? null : results[1];
}
function parse(string) {
items = string.split('?');
results = [];
for (var i in items) {
if (items[i].length == 0) continue;
var item = '?' + items[i];
results.push({
package: extract("Package", item),
qty: extract("Qty", item),
price: extract("Price", item)
})
}
return results;
}
str = "Package=Package&Qty=1&Price=123?Package=Package Two&Qty=3&Price=702?Package=Package Three&Qty=1&Price=199?Package=Package One&Qty=4&Price=852?";
document.getElementById('output').innerText = JSON.stringify(parse(str));
<div id='output'></div>
[NOTE: though similar to this stack question, my question differers significantly (IMO) due to the different structures of the initial variables. Mine is an array, the other questioner's is an object. My array contains nested objects/arrays, the latter of which contain name-value pairs whose values are, unlike the pairs in the other questioner's, not semantically identified.]
I have one big array (arr1) containing 24 objects. Each of the 24 objects contains one object, and one array of six further objects, like so:
var arr1 =
[
{'hour':1,'car':[{'audi':1377},{'bmw':716},{'ford':3819},{'mazda':67},{'toyota':11580},{'tesla':0}]},
{'hour':2,'car':[{'audi':1340},{'bmw':709},{'ford':3420},{'mazda':28},{'toyota':11583},{'tesla':0}]},
...etc, up to hour 24
];
As you can see, each of the 24 objects represents one hour's worth of data on car models and mileage. (What is NOT obvious is that the numeric value in each of the six objects represents miles.)
Now, I want to convert each object in arr1 into one array containing six objects, like below. So Hour 1's data in arr1 would convert to:
var arr2 = [{"car":"audi","miles":1377},{"car":"bmw","miles":716},{"car":"ford","miles":3819},{"car":"mazda","miles":67},{"car":"toyota","miles":11580},{"car":"tesla","miles":0}];
How can I do this? I have tried the following:
var hourx = 1;
var hour = arr1[hourx-1];
var car=hour.car;
for(var hourx1=0;hourx1<car.length;hourx1++){
var xx = car[hourx1];
var newobj = [];
for (var value in xx) {
var chartvar = newobj.push({car:value,miles:xx[value]});
var arr2 = newobj;
}
}
... but if I console.log(arr2); it only gives one array of one object.
I'm stumped. Anybody have an idea how I could accomplish this?
So you want to have an array of arrays as a final result?
var arr1 = [
{'hour':1,'car':[{'audi':1377},{'bmw':716},{'ford':3819},{'mazda':67},{'toyota':11580},{'tesla':0}]},
{'hour':2,'car':[{'audi':1340},{'bmw':709},{'ford':3420},{'mazda':28},{'toyota':11583},{'tesla':0}]}
];
var arr2 = arr1.map(function(hour){
return hour.car.map(function(car){
var carName = Object.keys(car)[0];
return {
"car": carName,
"miles": car[carName]
}
})
})
https://jsfiddle.net/1jjzeeyz/
Try using .map() , Object.keys()
var arr1 = [{
'hour': 1,
'car': [{
'audi': 1377
}, {
'bmw': 716
}, {
'ford': 3819
}, {
'mazda': 67
}, {
'toyota': 11580
}, {
'tesla': 0
}]
}, {
'hour': 2,
'car': [{
'audi': 1340
}, {
'bmw': 709
}, {
'ford': 3420
}, {
'mazda': 28
}, {
'toyota': 11583
}, {
'tesla': 0
}]
}];
var hours = arr1.map(function(cars, index) {
var carNames = Object.keys(cars.car);
var names = carNames.map(function(c) {
var name = Object.keys(cars.car[c])[0];
var res = {};
res["car"] = name;
res["miles"] = cars.car[c][name];
return res
})
return names
})
console.log(hours)
You would have to iterate over the array. Get the first property (let's hope it stays this way). Then get it value. Then create an object and add it to the array. See fiddle here
var arr1 =
[
{'hour':1,'car':[{'audi':1377},{'bmw':716},{'ford':3819},{'mazda':67},{'toyota':11580},{'tesla':0}]},
{'hour':2,'car':[{'audi':1340},{'bmw':709},{'ford':3420},{'mazda':28},{'toyota':11583},{'tesla':0}]},
];
var arr = [];
for (var i = 0; i< arr1[0].car.length; i++){
var car = arr1[0].car[i];
var key = Object.keys(car)[0];
arr.push({
car: key,
miles: car[key]
});
}
a combination of reduce and map will help. /example:
var
arr1 =[
{'hour':1,'car':[{'audi':1377},{'bmw':716},{'ford':3819},{'mazda':67},{'toyota':11580},{'tesla':0}]},
{'hour':2,'car':[{'audi':1340},{'bmw':709},{'ford':3420},{'mazda':28},{'toyota':11583},{'tesla':0}]}
],
arr2 = arr1.reduce(function (collector, item) {
collector.push(item.car.map(function (car/*, idx, list*/) {
var
make = Object.keys(car)[0]
;
return {
"car" : make,
"miles" : car[make]
}
}));
return collector;
}, [])
;
console.log("arr2 : ", arr2);
I need to loop through array and each array in array that has extra values, push them to their parent array as separate item. I hope this makes sense..
This is the structure of my initial array:
{type:
[ 0:
value: "tomato"
],
[ 1:
{value: "apple",
[ extras:
[ 0: { value: "green" } ],
[ 1: { value: "red" } ]
]
],
[ 2:
value: "pineapple"
]
}
What the result would have to look like:
[type:
[ 0:
tomato
],
[ 1:
apple,
green,
red
],
[ 2:
pineapple
]
]
What I've tried and failed: (I also commented the error I get on right line)
var response = /* json of first codeblock in question is response from ajax */;
var items = JSON.parse( response );
var type = Object.keys( items )[0];
var myArray = []
var count = items[type].lenght;
//Loop through main items in "type"
for( i = 0; i < count; i++ ) {
var value = items[type][i][value];
myArray[type][i] = [value]; //Uncaught TypeError: Cannot set property '0' of undefined
if( items[type][i][extras] ) {
var extracount = items[type][i][extras].lenght;
//Loop through extras
for( k = 0; k < extracount; k++ ) {
var extra = items[type][i][extras][k][value];
myArray[type][i].push( extra );
}
}
}
My main problem that I don't understand and that seems to be the problem in my example as well:
If I declare an empty array, how do I:
push an item to that array also declaring a new array around that item?
push another item to that array that was made around the first item?
This is what I believe you want. The following code may be incorrect, because I'm approximating what I believe your items object contains.
var items = {
type: [
{
value: "tomato"
},
{
value: "apple",
extras: [
{
value: "green"
}, {
value: "red"
}
]
},
{
value: "pineapple"
}
]
};
var myArray = {
type: []
};
var count = items['type'].length;
//Loop through main items in "type"
for (i = 0; i < count; i++) {
var subarray = [];
subarray.push(items['type'][i]['value']);
if (items['type'][i]['extras']) {
var extracount = items['type'][i]['extras'].length;
//Loop through extras
for (k = 0; k < extracount; k++) {
var extra = items['type'][i]['extras'][k]['value'];
subarray.push(extra);
}
}
myArray['type'].push(subarray);
}
Some notes:
You will definitely need to learn the difference between an array and an object in javascript. There are plenty of resources online for this.
When retrieving/manipulating a property prop from an object obj (i.e. for a key-value pair), you will need to use obj.prop or obj['prop']. Note the use of a string in the latter example.
For an array arr, you should use arr.push(value) to push a new value onto the array.
Your problem is here:
var value = items[type][i][value];
you should change it to
var value = items[type][i].value;
I'm new to javascript. I am trying to store object variable names in an array but the way I'm doing it, the array values become strings. Is there a way to change these values from strings to the object variable names? In the following code, the last statement is what I would like to use but it generates "undefined" because, I think, it's seen as a string. Thanks!
var plan1 = {
name: "Lisa",
price: 5.00,
space: 100
}
var plan2 = {
name: "John",
price: 2.00,
space: 150
}
var myArray = [];
for (var i = 0; i < 2; i++) {
myArray[i] = "plan" + (i + 1);
}
alert(plan2.name);
alert(myArray[1].name);
Disclaimer: it's a very bad style, try to avoid it. Look at http://nedbatchelder.com/blog/201112/keep_data_out_of_your_variable_names.html
You can consider using eval:
for (var i = 0; i < 2; i++) {
myArray[i] = eval("plan" + (i + 1));
}
You can't build the name like you are trying to do and get it to store the object with the same name. What you have in myArray is the strings "plan1" and "plan2".
You would have to do something like myArray[0] = plan1; myArray[1] = plan2; Then it should work in the array like you want it to.
Don't try to do that programmatically. Just build your array literal out of the parts that you want it to contain:
var plan1 = {
name: "Lisa",
price: 5.00,
space: 100
};
var plan2 = {
name: "John",
price: 2.00,
space: 150
};
var myArray = [plan1, plan2];
Or even don't use those variables for the objects at all, and directly put them in the array structure:
var myArray = [{
name: "Lisa",
price: 5.00,
space: 100
}, {
name: "John",
price: 2.00,
space: 150
}];
you can use
myArray[i] = window["plan" + (i + 1)];
working copy at http://plnkr.co/edit/7pY4Lcmx6wN1rQk9rklu?p=preview
Let's say I have an array:
var myArr = new Array('alpha','beta','gamma','delta');
And that I want a function to return an array of all items before a given item:
function getAllBefore(current) {
var myArr = new Array('alpha','beta','gamma','delta');
var newArr = ???
return newArr;
}
getAllBefore('beta'); // returns Array('alpha');
getAllBefore('delta'); // returns Array('alpha','beta','gamma');
What's the fastest way to get this? Can I split an array on a value? Do I have to loop each one and build a new array on the fly? What do you recommend?
What about if I wanted the opposite, i.e. getAllAfter()?
function getAllBefore(current) {
var myArr = new Array('alpha','beta','gamma','delta');
var i = myArr.indexOf(current);
return i > -1 ? myArr.slice(0, i) : [];
}
Get the index of the specified item. If found, .slice() from 0 to that index. If not found, return an empty array (or whatever other default value you like).
Note that .indexOf() is not supported (for arrays) in IE8 and older, but there is a shim you can use, or you could just use a simple for loop instead.
javascript slice array
// array.slice(start, end)
const FRUITS = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
var citrus = FRUITS.slice(1, 3);
// citrus => [ 'Orange', 'Lemon' ]
// Negative values slice in the opposite direction
var fromTheEnd = FRUITS.slice(-3, -1);
// fromTheEnd => [ 'Lemon', 'Apple' ]
array cut only last 5 element
arr.slice(Math.max(arr.length - 5, 0))
Use indexOf and slice:
newArr = myArr.slice(0, myArr.indexOf(current));
Try something like this
var index = myArr.indexOf('beta');
var before = myArray.slice(0, index);
I recently had to do something like this for an array of objects. This is what I went with:
const myArr = [
{ controlId: 1, value: 'alpha'},
{ controlId: 2, value: 'beta' },
{ controlId: 3, value: 'gamma' },
{ controlId: 4, value: 'delta'}
];
function getAllBefore(id) {
const index = myArr.findIndex( ({ controlId }) => controlId === id);
return myArr.filter((_, i) => i < index);
}