How to combine same strings in array? - javascript

I am making my first project as a food rota that gives out a shopping list from the chosen Recipe ingredients.
I managed to write the loop that would combine all the ingredients in one array where it takes us to my question.
I would like to combine the same ingredients in the array ie: [1kg Carrots, 1kg Spinach, 1kg Carrots], I would like it to combine the repeating (1kg Carrots, 1kg Carrots) into (2kg Carrots)
Is there a way to do this?
Sorry if my request is sloppy, first time asking a question.
I could work it so that it would cancel out the similar ones as the outcome of [1kg Carrots, 1kg Carrots] would be [1kg Carrot].
Unfortunately I am at work at the moment and do not have access - will update if needed.

I would most likely create an object from the array.
const arr = ['1kg Carrots', '1kg Spinach', '1kg Carrots'];
let obj = {};
arr.forEach(element => {
let [kg, item] = element.split(' ');
kgNum = parseInt(kg);
if(Object.keys(obj).includes(item)){
return obj[item] += kgNum;
} else {
obj[item] = kgNum;
}
})
obj
// #=> { Carrots: 2, Spinach: 1 }
I loop over the array
I split the element (eg. '1kg Carrots') into the weight and item
then I coerce the 1kg into an integer
I check if the obj already has a key of item and if it doesn't I add it
If it does already exist I just increment kgNum
and then I return the object
This is a good place to start and you can figure out with a little more work of how to add back the kg :)

it can be done in 2 steps
var arr = ["1kg Carrots", "1kg Spinach", "1kg Carrots"]
step 1: count total number of kg
var arrCount = arr.reduce((ac, val)=> {
var [kg, key] = val.split(' ')
kg = parseFloat(kg)
ac[key] = ac[key]? ac[key]+kg : kg;
return ac
}, {}) // { Carrots: 2, Spinach: 1 }
step 2: revert it to array
var out = Object.entries(arrCount).map(([key, kg])=> `${kg}kg ${key}`)
// [2kg Carrots, 1kg Carrots]

Related

Return / Get x Number of Items From an Array in Typescript/Javascript

I have an array with over 200 items from a .json file.
I want to know how I can return lets say the first 10 items or 20 items starting from the 7th index/item.
Example
OriginalArray = [{a}, {b}, {c}, {d}, {e}, {f}, {g}, {h}, {i}, {j}, {k}, {l}]
How do I get newArray = [{a}, {b}, {c}, {d}] or newArray = [{e}, {f}, {g}, {h}]
from the originalArray in typeScript or Javascript.
Thank you
Try this:
newArrayA = OriginalArray.slice(0, Math.round(OriginalArray.length/2)) // first half
newArrayB = OriginalArray.slice(Math.round(OriginalArray.length/2)) // second half
You need slice
const offset = 7;
console.log(
["{a}", "{b}", "{c}", "{d}", "{e}", "{f}", "{g}", "{h}", "{i}", "{j}", "{k}", "{l}"]
.slice(offset,offset+4)
)
In your case:
var newArray = OriginalArray.slice(7, 7+20);

How can I get specific keys from this?

I've used hasOwnProperty and typeof in the past but this one is stumping me...
I'm trying to get all the keys that have keys that match so I can pair them with other keys example:
{"meals": [{
strIngredient1 : lemons
strIngredient2 : paprika
strIngredient3 : red onions
strIngredient4 : chicken thighs
strIngredient5 : vegetable oil
strMeasure1 : 2 Juice
strMeasure2 : 4 tsp
strMeasure3 : 2 finely chopped
strMeasure4 : 16 skinnless
strMeasure5 :
}]}
It's apparent that strIngredient1 matches with strMeasure1 etc...
Any suggestions or help would be greatly appreciated!!
Explained
In this example, you can see that I've provided the solution in two parts, one being a simple way to simply access 'x' ingredient from the array of meals, then another solution which will iterate over the array of meals, printing out each individual ingredient.
As I've stated within my solution, you can use forEach or alternatively, you can also use functions such as map or reduce if you wish. In the event that you don't know when to use which, the basic rule of thumb is that you'd use map or reduce if you wish to follow functional programming concepts. The forEach solution allows for side effects to happen more easily, etc... I mean this is debatable to a certain extent, but that's the basic idea anyways...
Edit
I've included a simple log function just for this demo, long story short, when you run this code snippet, personally I find it disgusting how little space is provided for the console window, so log one thing at a time after some delay and clear the console too.
let delay = 0;
const DELAY_INC = 1500;
// Just for this demo, have the ability to log something,
// after a delay and clear the console.
const log = (arg, alrt) => {
setTimeout(() => {
console.clear();
console.log(arg);
if (alrt != null) {
alert(alrt);
}
}, delay);
delay += DELAY_INC;
};
// Your data.
var data = {
"meals": [{
strIngredient1: 'lemons',
strIngredient2: 'paprika',
strIngredient3: 'red onions',
strIngredient4: 'chicken thighs',
strIngredient5: 'vegetable oil',
strMeasure1: '2 Juice',
strMeasure2: '4 tsp',
strMeasure3: '2 finely chopped',
strMeasure4: '16 skinnless',
strMeasure5: ''
}]
};
// Just some demo.
var meals = data.meals;
var meal = meals[0];
var ingredient = meal.strIngredient1;
log(data); // Log the raw data.
log(meals); // Log the array of meals.
log(meal); // Log a specific meal.
log(ingredient); // Log a specific ingredient.
// If you wish to iterate, log each ingredient for each meal.
data.meals.forEach(meal => Object.keys(meal).forEach(key => log(meal[key])));
// Here's a solution.
const newArray = data.meals.reduce((array, meal) => {
// Rather than iterate over ALL of the keys, just
// do this, basically 50% of the keys.
const subArray = Object.keys(meal).filter(key => key.indexOf('strIngredient' == -1));
// Basically add some ojects to the array.
subArray.forEach(key => {
const int = key.replace(/\D/g, '');
const measureKey = `strMeasure${int}`;
const ingredientKey = `strIngredient${int}`;
const obj = {
ingredient: meal[ingredientKey],
measure: meal[measureKey]
};
array.push(obj);
});
// Make sure to return the array.
return array;
}, []);
// Now just print the resuts, and make sure that you know
// and alert that the app has finished.
log(newArray, 'FINISHED');
For those interested or if it helps anyone here is the final product! All neat and tidy in one array, easy to use! :) Thank you again JO3-W3B-D3V!
getRecipe: function(url) {
request({
url: url,
method: 'GET'
}, (error, response, body) => {
if (!error && response.statusCode == 200) {
var result = JSON.parse(body);
//console.log(result);
// Just some TESTING.
var meals = result.meals; //returns array
var meal = meals[0]; // returns object
//console.log(meal);
// Start here to rename keys and match them to the ingredients.
const newArray = meals.reduce((array, meal) => {
// Rather than iterate over ALL of the keys, just
// do this, basically 50% of the keys.
const subArray = Object.keys(meal).filter(key => key.indexOf('strIngredient' == -1));
// console.log(subArray);
// Basically add some ojects to the array.
subArray.forEach(key => {
const int = key.replace(/\D/g, '');
const measureKey = `strMeasure${int}`;
const ingredientKey = `strIngredient${int}`;
const obj = {
measure: meal[measureKey],
ingredient: meal[ingredientKey]
};
// console.log(obj); //Testing data before
if (obj.measure && obj.ingredient != 'undefined' || undefined || "" || null){
array.push(obj);
// console.log(array); //Testing data after
}
});
const recipeName = meal.strMeal;
const instruction = meal.strInstructions;
const video = meal.strYoutube;
const thumb = meal.strMealThumb;
const nation = meal.strArea;
const category = meal.strCategory;
const recipe = {recipeName, instruction, video, thumb, nation, category};
array.push(recipe);
//console.log(recipe); Testing full array
// Make sure to return the array.
return array;
}, []);
// Now just print the resuts, and make sure that you know
// and alert that the app has finished.
console.log(newArray, "FINISHED");

Generating a new array if a certain criteria is met (Javascript)

I have an array of users who all need to be added to a group array. If the the group array has less than 3 users, i want to add the user to that group array. If the group array already has 3 user, I want to push the current group array to another array that collects all the groups and start another new group array for the next 3 users until there are no users.
Error -
let group[i] = [];
Unexpected token [
I have been racking my brains trying to figure this out. Maybe staring at the screen for too long.
This is what i have been trying with different variations but the console is not impressed -
function createGroups(totalPeople){
let i = 1
let group[i] = [];
let array = totalPeople
totalPeople.map((user) => {
if(group[i] =< 3){
group[i].push(user)
}else{
array.push(group[i]);
i++
}
})
};
totalPeople is an array created earlier in my code and this is the only part of the file that is not running as intended. Any help with a method on how to do this or suggestions on fixing this code would be of great help! thank you!
Try to initialize group as an array:
let i = 1
let group = [] // Initialize as an array
group[i] = [];
let array = totalPeople
totalPeople.map((user) => {
if(group[i] =< 3){
group[i].push(user)
}else{
array.push(group[i]);
i++
}
})
There are a few issues in your code :
function createGroups(totalPeople){
let i = 1
let group[i] = []; // issue #1
let array = totalPeople
totalPeople.map((user) => {
if(group[i] =< 3){ // issues #2 and #3
group[i].push(user)
}else{
array.push(group[i]); // issue #4
i++; // issue #5
}
})
};
Issue #1 :
You need to define group as an array before adding an index.
let group = [];
group[i] = [];
Issue #2 :
Looks like you meant to compare group[i].length and 3
Issue #3 :
Use <= instead of =< to compare your numbers. Also, if you compare the length with <= 3, you'll have 4 people per group. Because the first index in arrays is 0.
Issue #4 :
You are pushing to array, which is a reference to totalPeople. Is this what you meant? Because I doubt it will produce the expected results. You may want to initialize an empty array and push your group[i] array in it. And then, return that new array. It's usually a good practice in functionnal programming to return a new array and not modify the one passed as a parameter.
Issue #5 :
If you increment i, you need to initialize group[i] as an array, otherwise you won't be able to push in it when comes the next loop iteration.
Differnet logic :
Now that you fixed the issues in your code, here's a Snippet showing another way to do it using Array.prototype.reduce :
const totalPeople = ["Joe", "Jack", "Jerry", "Jane", "Mary", "Billy", "Vicky", "Bobby"];
const groupsOfThree = totalPeople.reduce((accumulator, currentPerson, index) => {
// pushing the current person in the topest group in the accumulator
accumulator[accumulator.length-1].push(currentPerson);
// if it's the 3rd person, we're pushing the an empty group in the accumulator
if (index % 3 === 2) {
accumulator.push([]);
}
return accumulator;
}, [[]]); // the initial value of the accumulator will be an array containing an empty group
console.log(groupsOfThree);

Separate strings in an array in a certain order

I have a list that I took from a converted CHANGELOG.md file, and it looks like this:
["[3.0.0]","Features", "changes done in file","[2.0.1]", "Bug Fixes", "fixed login"]
What I want to do is to separate each version into its own list, like this:
["[3.0.0]", "Features", "changes done in file"],
["[2.0.1]", "Bug Fixes", "fixed login"]
Obviously, because it's a changelog, there can be multiple features and multiple bugfixes in a single version, so I want to a piece of code that separates the code appropriately.
I tried using if (string.startsWith('[')) but i couldn't manage to fit it in a loop.
Any help is appreciated.
Here's something I came up with. The code basically loops through the input array and adds each string to a currentArray variable. Everytime it hits a [ it puts the currentArray into the output and clears currentArray. At the end it removes the first element as the first element of the output will always be an empty array (since the first element of the input starts with a [)
var input = ["[3.0.0]","Features", "changes done in file","[2.0.1]", "Bug Fixes", "fixed login"];
var output = [];
var currentArray = [];
for (var i = 0; i < input.length; i++) {
if (input[i].charAt(0) == '[') {
output.push(currentArray);
currentArray = [];
}
currentArray.push(input[i]);
}
output.push(currentArray);
currentArray = [];
//Since it will take the first one, and put empty one, need to do last step.
output.splice(0, 1);
console.log(output);
// ["[3.0.0]", "Features", "changes done in file"],
// ["[2.0.1]", "Bug Fixes", "fixed login"]
Assuming that you're always working in sets of three, this is a quick and ugly approach
var data = ["[3.0.0]","Features", "changes done in file","[2.0.1]", "Bug Fixes", "fixed login"],
items = [];
data.map( (el, idx) => {
var last = items.length;
if( idx % 3 === 0 ) {
items.push( [] );
last += 1;
}
last = items[ last - 1 ];
last.push( el );
} );
console.log( JSON.stringify( items ) );
Here's an alternative solution should you prefer it:
const arr = ["[3.0.0]","Features", "changes done in file","[2.0.1]", "Bug Fixes", "fixed login"];
const newArr = [];
let tempArr = [];
arr.forEach(function(v, i) {
if(/^\[\d+.\d+.\d\]$/.test(v) && i > 0) {
newArr.push(tempArr);
tempArr = [v];
} else {
tempArr.push(v)
}
});
newArr.push(tempArr);
console.log(newArr);
This snippet loops through the items one-by-one. It uses two arrays, one to hold the final result and one to populate with items for the current version.
I am using a regex to check if the item contains one [ followed by a number, then a period, number, period, number and finally the trailing ]. This allows the other strings that are not version tags to contain that character.
If the current item is a version tag, we push tempArr (which contains the changes of the current version that we've previously filled in our loop) to our result array newArr. Then, we empty the tempArr and give it the starting value of the next version tag.
If it is not, we just push the current item to our temporary array.
It would be interesting to know if you were guaranteed to get this data in triplets, as your example seems to imply. If you knew this up front, there are many creative solutions that could emerge. For just creating a 2D Array, however, I like this approach (you can run this directly in node.js to try it out):
const original = ['[3.0.0]', 'Features', 'changes done in file', '[2.0.1]', 'Bug Fixes', 'fixed login']
function transformToChangeLog (originalArray) {
const changeLog = originalArray.reduce((newList, element) => {
element.charAt(0) === '[' // check for version string
? newList.push([element]) // If version string, then push a new Array containing that string
: newList[newList.length - 1].push(element) // If something else, tack it onto the last Array in the changelog list
return newList // whatever is returned in the reduce function is passed to the next iteration, allowing us to build this 2D array one element at a time.
}, [])
return changeLog
}
console.log(transformToChangeLog(original))
I hope that helps! I like the reduce Array method, because of it's versatility and succinctness.

Split an object into array of objects based on a condition in JavaScript

How to split an object into array of objects based on a condition.
oldObject = {"Chicago, IL:Myrtle Beach, SC": 0.005340186908091907,
"Portsmouth, NH:Rock Hill, SC": 0.0063224791225441205,
"Columbia, SC:Laconia, NH": 0.006360767389277389,
"Council Bluffs, IA:Derry, NH": 0.0016636141225441225}
Above is the given sample object. I want to make an array of objects like this,
newArray = [{"city":"Chicago", "similarTo":"Myrtle"},
{"city":"Portsmouth", "similarTo":"Rock Hill"},
{"city":"Columbia", "similarTo":"Laconia"},
{"city":"Council Bluffs", "similarTo":"Derry"}]
I have been scratching my head with this for a while now. How can I get the above array(newArray)?
Here is a bunch of code you can try.
1) Iterate over oldObject and get the name of the property.
2) Split that name into an array based on the ":" character, since it separates the cities
3) Go over that new array, splitting it on the "," character (so as not to get the states).
4) Put the values into the newObject, based on whether it's the first or second part of the original property name.
5) Push that newObject, now with items, into a newArray.
Basically, this parses apart the name and does some array splitting to get at the right values. Hope it helps and helps you understand too.
var oldObject = {"Chicago, IL:Myrtle Beach, SC": 0.005340186908091907,
"Portsmouth, NH:Rock Hill, SC": 0.0063224791225441205,
"Columbia, SC:Laconia, NH": 0.006360767389277389,
"Council Bluffs, IA:Derry, NH": 0.0016636141225441225};
var newArray = [];
for (object in oldObject) {
var thisObjectName = object;
var thisObjectAsArray = thisObjectName.split(':');
var newObject = {
'city': '',
'similar_to': ''
};
thisObjectAsArray.forEach(function(element,index,array) {
var thisObjectNameAsArray = element.split(',');
var thisObjectNameCity = thisObjectNameAsArray[0];
if(index===0) {
newObject.city = thisObjectNameCity;
} else if(index===1) {
newObject.similar_to = thisObjectNameCity;
}
});
newArray.push(newObject);
}
console.log(newArray);
PS: to test, run the above code and check your Developer Tools console to see the new array output.

Categories