I am attempting to extract JSON values (from structure called jsonWithListOfStatesAndCounters) if it matches with an element in my inputted array (inputedJurisdictionArray). My inputed array contains sting values that include singular or multiple state names (i.e. var inputedJurisdictionArray = ["Iowa", "California, Indiana, Delaware", "Florida"]). The singular State values in this array are handled normally at the end, but the multiple state values is where it gets tricky. I am using split() in order to turn them into another array so they can get processed one by one. Anytime one of the states from this inputed array matches with a "state" value in jsonWithListOfStatesAndCounters, I am extracting it into another JSON structure and pushing it at the end of every block into my initial variable myJurisdictionJSON. The problem I am having is that once these forEach loops are completed, I am still left with my original values in myJurisdictionJSON, instead of the val and counter that should be extracted. The jsonWithListOfStatesAndCounters definitely contains the values that should match with the elements of my inputedJurisdictionArray, but the information is not being pushed into myJurisdictionJSON. What am I doing wrong? Any tips/pointers will be helpful.
var myJurisdictionJSON = [{
jurisdiction_val: 'jurisdiction_val',
jurisdiction_counter: 'jurisdiction_counter'
}];
inputedJurisdictionArray.forEach(function each(item) {
if (Array.isArray(item)) {
item.forEach(each);
} else {
var jurisdictionInput = item;
jsonWithListOfStatesAndCounters.forEach(function each(item) {
if (Array.isArray(item)) {
item.forEach(each);
} else {
if (jurisdictionInput.includes(",") === true){//Checking if more than one jurisdiction in string
var jurisdictionArr = jurisdictionInput.split(", ");
var jurisdictionCounter = item.jurisdictionCounter;
var jurisdictionState = item.jurisdictionState;
jurisdictionArr.forEach(function(element) {
if (myJurisdictionJSON.jurisdiction_counter == 'jurisdiction_counter'){ // If nothing is pushed into our predefined JSON object
if (jurisdictionState.toLowerCase() == trim(element.toLowerCase())) {
var jurisdictionJSON_inner = {
jurisdiction_val: element,
jurisdiction_counter: jurisdictionCounter
};
myJurisdictionJSON.push(jurisdictionJSON_inner);
return;
}
}else if (myJurisdictionJSON.jurisdiction_counter != 'jurisdiction_counter'){ // if an item has been pushed into myJurisdictionJSON, append the next items
var jurisdictionCounter = item.jurisdictionCounter;
var jurisdictionState = item.jurisdictionState;
if (jurisdictionState.toLowerCase() == trim(jurisdictionInput.toLowerCase())) {
jurisdictionJSON_inner.jurisdiction_val = jurisdictionJSON_inner.jurisdiction_val + ", " + jurisdictionInput;
jurisdictionJSON_inner.jurisdiction_counter = jurisdictionJSON_inner.jurisdiction_counter + ", " + jurisdictionCounter;
myJurisdictionJSON.push(jurisdictionJSON_inner);
return;
}
}
});
}
else{// if only one jurisdiction state in jurisdictionInput string
var jurisdictionCounter = item.jurisdictionCounter;
var jurisdictionState = item.jurisdictionState;
if (jurisdictionState.toLowerCase() == trim(jurisdictionInput.toLowerCase())) {
var jurisdictionJSON_inner = {
jurisdiction_val: jurisdictionInput,
jurisdiction_counter: jurisdictionCounter
};
myJurisdictionJSON.push(jurisdictionJSON_inner);
return;
}
}
}
});
I'm not totally sure the output is what you want but it's close.
// input data as per your example
let inputedJurisdictionArray = [
'Iowa',
'California, Indiana, Delaware',
'Florida'
];
// I had to make this part up. It's missing from the example
let jsonWithListOfStatesAndCounters = [{
jurisdictionCounter: 2,
jurisdictionState: 'Florida'
},
{
jurisdictionCounter: 4,
jurisdictionState: 'Indiana'
},
{
jurisdictionCounter: 3,
jurisdictionState: 'Texas'
}
];
// first, fix up inputedJurisdictionArray
// reduce() loops over each array element
// in this case we're actually returning a LARGER
// array instead of a reduced on but this method works
// There's a few things going on here. We split, the current element
// on the ','. Taht gives us an array. We call map() on it.
// this also loops over each value of the array and returns an
// array of the same length. So on each loop, trim() the whitespace
// Then make the accumulator concatenate the current array.
// Fat arrow ( => ) functions return the results when it's one statement.
inputedJurisdictionArray = inputedJurisdictionArray.reduce(
(acc, curr) => acc.concat(curr.split(',').map(el => el.trim())), []
);
// now we can filter() jsonWithListOfStatesAndCounters. Loop through
// each element. If its jurisdictionState property happens to be in
// the inputedJurisdictionArray array, then add it to the
// myJurisdictionJSON array.
let myJurisdictionJSON = jsonWithListOfStatesAndCounters.filter(el =>
inputedJurisdictionArray['includes'](el.jurisdictionState)
);
console.log(myJurisdictionJSON);
Related
I have following JSON objects in one of my parser programs written years ago.
{"Date":"19/02/16","Narration":"NEFT DR-BARB0PIMPAL-Govt. NE","Chq":{"/Ref":{"No":{"":"N050160130709970"}}},"Value Dt":"19/02/16","Withdrawal Amt":{"":"8,000.00"},"Deposit Amt":{"":""},"Closing Balance":"24,114.95"}
{"Date":"","Narration":"TBANK, MUM-N050160130709970","Chq":{"/Ref":{"No":{"":""}}},"Value Dt":"","Withdrawal Amt":{"":""},"Deposit Amt":{"":""},"Closing Balance":""}
Basically, the above entry should have been a single record. However, due to line wrapping the parser treating them as a new record.
I tried mapping the objects by converting them into an array. However, then the map resulted as the following JSON object.
{"Date":"19/02/16"}{"Date":""},{"Narration":"NEFT DR-BARB0PIMPAL-Govt. NE"}{"Narration":"TBANK, MUM-N050160130709970"},{"Chq":{"/Ref":{"No":{"":"N050160130709970"}}}}{"Chq":{"/Ref":{"No":{"":""}}}},{"Value Dt":"19/02/16"}{"Value Dt":""},{"Withdrawal Amt":{"":"8,000.00"}}{"Withdrawal Amt":{"":""}},{"Deposit Amt":{"":""}}{"Deposit Amt":{"":""}},{"Closing Balance":"24,114.95"}{"Closing Balance":""}
What I need to have is a merged/combined array OR object with main keys remain intact and values join/append to the first element (second object to be discarded thereafter.)
For example.
{"Date":"19/02/16","Narration":"NEFT DR-BARB0PIMPAL-Govt.NETBANK","Chq":{"/Ref":{"No":{"":"N050160130709970MUM-N050160130709970"}}},"Value Dt":"19/02/16","Withdrawal Amt":{"":"8,000.00"},"Deposit Amt":{"":""},"Closing Balance":"24,114.95"}
Can you guys suggest if I can directly merge/combine the source JSON Object or merge the arrays with above effects?
Obviously you would need to know the order of these objects, so I will assume you have an array of them, all parsed from JSON into JavaScript objects.
Secondly, I assume that a record that is a continuation of the previous one can be recognised by an empty balance field (for instance -- adapt as needed).
Here is code to perform the merge:
function mergeSplitObjects(arr) {
return arr.filter( (curr, i) => {
// Does this look like a split-off object that should be merged with previous?
if (curr["Closing Balance"] !== "") { // Adapt condition as needed
return true; // No, it is a real record
}
arr[i-1]["Narration"] += curr["Narration"]; // Merge, and filter curr out
});
}
// Sample data with 3 records. First two should be merged
let arr = [
{"Date":"19/02/16","Narration":"NEFT DR-BARB0PIMPAL-Govt. NE","Chq":{"/Ref":{"No":{"":"N050160130709970"}}},"Value Dt":"19/02/16","Withdrawal Amt":{"":"8,000.00"},"Deposit Amt":{"":""},"Closing Balance":"24,114.95"},
{"Date":"","Narration":"TBANK, MUM-N050160130709970","Chq":{"/Ref":{"No":{"":""}}},"Value Dt":"","Withdrawal Amt":{"":""},"Deposit Amt":{"":""},"Closing Balance":""},
{"Date":"20/02/16","Narration":"ATM NYC 13","Chq":{"/Ref":{"No":{"":"N050160130709971"}}},"Value Dt":"20/02/16","Withdrawal Amt":{"":"1,000.00"},"Deposit Amt":{"":""},"Closing Balance":"23,114.95"},
];
arr = mergeSplitObjects(arr);
console.log(arr);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I would use a function similar to Object.assign.
Just like Trincot, I assume Closing Balance to be an indication for records to merge.
var splitRegExp = /[a-z],\s*[a-z]/gi;
function deepMergingAssign(obj /*, sourceObjects*/){
'use strict';
if (obj == null) throw new TypeError('Cannot convert undefined or null to object');
var final = Object(obj);
[].slice.call(arguments, 1).forEach(function(arg){
if(arg != null) {
for(var prop in arg) {
if (typeof arg[prop] === 'object'&&typeof final[prop] === 'object') {
// recursively call this function
arg[prop] = deepMergingAssign(final[prop],arg[prop]);
delete arg[prop]
}
else if(Object.prototype.hasOwnProperty.call(arg,prop)) {
// append the new values to the existing value.
var currentValue = final[prop].split(splitRegExp);
var incomingValue = arg[prop].split(splitRegExp);
incomingValue.forEach( function(val){
if (val! == '' && currentValue.indexOf(val) === -1) currentValue.push(val);
});
final[prop] = currentValue.join(', ');
}
}
}
});
return final;
}
function mergeRecords(records){
var toMerge = [];
var mergedData = []
for (var i=0; i<records.length; i++){
// Change this condition as needed
if (records[i]['Closing Balance'] !== '' && toMerge.length>0){
// Create a merged record and reset the toMerge variable
mergedData.push(deepMergingAssign.apply(null, toMerge));
toMerge = [records[i]];
}
else {
// This record should be merged with the previous.
toMerge.push(records[i]);
}
}
// Merge the last records stored in the array
mergedData.push(deepMergingAssign.apply(null, toMerge));
return mergedData;
}
var allRecords = [
{"Date":"19/02/16","Narration":"NEFT DR-BARB0PIMPAL-Govt. NE","Chq":{"/Ref":{"No":{"":"N050160130709970"}}},"Value Dt":"19/02/16","Withdrawal Amt":{"":"8,000.00"},"Deposit Amt":{"":""},"Closing Balance":"24,114.95"},
{"Date":"","Narration":"TBANK, MUM-N050160130709970","Chq":{"/Ref":{"No":{"":""}}},"Value Dt":"","Withdrawal Amt":{"":""},"Deposit Amt":{"":""},"Closing Balance":""},
{"Date":"21/02/16","Narration":"TBANK","Chq":{"/Ref":{"No":{"":"N050160130709971"}}},"Value Dt":"21/02/16","Withdrawal Amt":{"":""},"Deposit Amt":{"":"2,000.00"},"Closing Balance":"26,114.95"},
{"Date":"22/02/16","Narration":"TBANK","Chq":{"/Ref":{"No":{"":"N050160130709972"}}},"Value Dt":"22/02/16","Withdrawal Amt":{"":"5,750.00"},"Deposit Amt":{"":"1,000.00"},"Closing Balance":"21,364.95"},
{"Date":"","Narration":"TBANK, MUM-N050160130709972","Chq":{"/Ref":{"No":{"":""}}},"Value Dt":"","Withdrawal Amt":{"":""},"Deposit Amt":{"":""},"Closing Balance":""}
]
var merged = mergeRecords(allRecords);
/* [
record 1+2,
record 3,
record 4+5
] */
I'm brand new to programming so I apologize if this is a simple question.
I had a unique practice problem that I'm not quite sure how to solve:
I'm dealing with two arrays, both arrays are pulled from HTML elements on the page, one array is representing a bunch of states, and the next array is representing their populations. The point of the problem is to print the name of the states and their less than average populations.
To find and print all of the populations that are less than the average I used this code:
function code6() {
// clears screen.
clr();
// both variables pull data from HTML elements with functions.
var pop = getData2();
var states = getData();
var sum = 0;
for( var i = 0; i < pop.length; i++ ){
sum += parseInt( pop[i], 10 );
var avg = sum/pop.length;
if (pop[i] < avg) {
println(pop[i]);
// other functions used in the code to get data, print, and clear the screen.
function getData() {
var dataSource = getElement("states");
var numberArray = dataSource.value.split('\n');
// Nothing to split returns ['']
if (numberArray[0].length > 0) {
return(numberArray);
} else {
return [];
}
}
// Get the data from second data column
function getData2() {
var dataSource = getElement("pops");
var numberArray = dataSource.value.split('\n');
// Nothing to split returns ['']
if (numberArray[0].length > 0) {
return(numberArray);
} else {
return [];
}
}
// Clear the 'output' text area
function clr() {
var out = getElement("output");
out.value = "";
}
// Print to the 'output' HTML element and ADDS the line break
function println(x) {
if (arguments.length === 0) x = '';
print(x + '\n');
}
Now I just need to know how to get the value of these positions within the array so I can pull out the same positions from my states array and display them both side by side. Both arrays have the identical amount of items.
I hope this makes sense and thanks in advance to anyone who has time to take a look at this.
Best regards,
-E
Its a little hard to tell what you are trying to accomplish, but I guess you are going for something like:
'use strict'
function code6() {
const populations = ['39000000', '28000000', '21000000'];
const stateNames = ['california', 'texas', 'florida'];
const states = populations.map((population, i) => ({
'name': stateNames[i],
'population': Number(population),
}));
const sum = states.reduce((sum, state) => sum + state.population, 0);
const average = sum / populations.length;
states
.filter(state => state.population < average)
.forEach(state => {
const name = state.name;
const population = state.population;
console.log(`state name: ${name}, population: ${population}`);
});
}
// run the code
code6();
// state name: texas, population: 28000000
// state name: florida, population: 21000000
I took the liberty of refactoring your code to be a little more modern (es6) and Idiomatic. I hope its not to confusing for you. Feel free to ask any questions about it.
In short you should use:
'use strict' at the top of your files
const/let
use map/filter/forEach/reduce to iterate lists.
use meaningfull names
, and you should avoid:
classic indexed for-loop
parseInt
, and pretty much never ever use:
var
If your states array is built with corresponding indices to your pop one, like this:
states; //=> ['Alabama', 'Alaska', 'Arizona', ...]
pop; //=> [4863300, 741894, 6931071, ...]
then you could simply update your print statement to take that into account:
if (pop[i] < avg) {
println(state[i] + ': ' + pop[i]);
}
Or some such.
However, working with shared indices can be a very fragile way to use data. Could you rethink your getData and getData2 functions and combine them into one that returns a structure more like this the following?
states; //=> [
// {name: 'Alabama', pop: 4863300}
// {name: 'Alaska', pop: 741894},
// {name: 'Arizona', pop: 6931071},
// ...]
This would entail changes to the code above to work with the pop property of these objects, but it's probably more robust.
If your pop and state looks like:
var state = ['state1', 'state2', ...];
var pop = ['state1 pop', 'state2 pop', ...];
Then first of all, avg is already wrong. sum's value is running along with the loop turning avg's formula into sum as of iteration / array length instead of sum of all pops / array length. You should calculate the average beforehand. array.reduce will be your friend.
var average = pop.reduce(function(sum, val){return sum + val;}, 0) / pop.length;
Now for your filter operation, you can:
Zip up both arrays to one array using array.map.
Filter the resulting array with array.filter.
Finally, loop through the resulting array using array.forEach
Here's sample code:
var states = ['Alabama', 'Alaska'];
var pop = [4863300, 741894];
var average = pop.reduce(function(sum, val){return sum + val;}) / pop.length;
console.log('Average: ' + average);
states.map(function(state, index) {
// Convert 2 arrays to an array of objects representing state info
return { name: state, population: pop[index] };
}).filter(function(stateInfo) {
console.log(stateInfo);
// Filter each item by returning true on items you want to include
return stateInfo.population < average;
}).forEach(function(stateInfo) {
// Lastly, loop through your results
console.log(stateInfo.name + ' has ' + stateInfo.population + ' people');
});
I am creating a dictionary app in React, I have loaded in the JSON dictionary which looks like this:
{
"DIPLOBLASTIC": "Characterizing the ovum when it has two primary germinallayers.",
"DEFIGURE": "To delineate. [Obs.]These two stones as they are here defigured. Weever.",
"LOMBARD": "Of or pertaining to Lombardy, or the inhabitants of Lombardy.",
"BAHAISM": "The religious tenets or practices of the Bahais.",
"FUMERELL": "See Femerell."
}
The user enters a word in the input field and the value is then passed into the following function to search for a matching key in the JSON. Matching words are then pushed into an array of results with their respective value.
handleSearch: function(term) {
var term = term;
var results = [];
for (var key in Dictionary) {
if (Dictionary.hasOwnProperty(key)) {
if (term == Dictionary[key]) {
results.push(Dictionary[key])
}
}
}
console.log(results)
},
However I am struggling to find a successful way of looping through it to get results. the console is logging an empty array.
Can anyone please suggest where I am going wrong?
You can have better matching by adding a compare function (in example below it is the compareTerm function). What I did there is comparing if the term STARTS with the dictionary key, if you want it to be any part of the string you can change it from === 0 to > -1.
// compare function which needs to be added somewhere
function compareTerm(term, compareTo) {
var shortenedCompareTo = compareTo
.split('')
.slice(0, term.length)
.join('');
return term.indexOf(shortenedCompareTo.toLowerCase()) === 0;
}
// only changed the compare function
handleSearch: function(term) {
var results = [];
for (var key in Dictionary) {
if (Dictionary.hasOwnProperty(key)) {
if (compareTerm(term, Dictionary[key])) {
results.push(Dictionary[key])
}
}
}
console.log(results);
},
My Json is like this:
[
{"isoCode":"BW","name":"Botswana ","CashOut":"Y","BankOut":"","MMT":null},
{"isoCode":"BR","name":"Brazil ","CashOut":"Y","BankOut":"Y","MMT":null},
{"isoCode":"BG","name":"Bulgaria ","CashOut":"Y","BankOut":"Y","MMT":"Y"},
{"isoCode":"BF","name":"Burkina Faso","CashOut":"Y","BankOut":"","MMT":null},
{"isoCode":"BI","name":"Burundi","CashOut":"","BankOut":"","MMT":"Y"},
{"isoCode":"KH","name":"Cambodia","CashOut":"Y","BankOut":"","MMT":null}
]
I want all the names which have BankOut value as "Y" into an array using JavaScript, in order to use those names in my protractor automation.
You need to use filter method of array. It takes function as it argument. And runs it against each element of array. If function returns true (or other truthy value) then that element stays in newly created array.
var list =[ {"isoCode":"BW","name":"Botswana ","CashOut":"Y","BankOut":"","MMT":null},
{"isoCode":"BR","name":"Brazil ","CashOut":"Y","BankOut":"Y","MMT":null},
{"isoCode":"BG","name":"Bulgaria ","CashOut":"Y","BankOut":"Y","MMT":"Y"},
{"isoCode":"BF","name":"Burkina Faso ", "CashOut":"Y","BankOut":"","MMT":null},
{"isoCode":"BI","name":"Burundi","CashOut":"","BankOut":"","MMT":"Y"},
{"isoCode":"KH","name":"Cambodia","CashOut":"Y","BankOut":"","MMT":null}
];
var onlyBankOutY = list.filter(function (item) {
return item.BankOut === 'Y';
});
document.body.innerHTML = onlyBankOutY.map(function (item) {
return JSON.stringify(item);
}).join('<br>');
var list =[
{"isoCode":"BW","name":"Botswana ","CashOut":"Y","BankOut":"","MMT":null},
{"isoCode":"BR","name":"Brazil ","CashOut":"Y","BankOut":"Y","MMT":null},
{"isoCode":"BG","name":"Bulgaria ","CashOut":"Y","BankOut":"Y","MMT":"Y"},
{"isoCode":"BF","name":"Burkina Faso ", "CashOut":"Y","BankOut":"","MMT":null}, {"isoCode":"BI","name":"Burundi","CashOut":"","BankOut":"","MMT":"Y"},
{"isoCode":"KH","name":"Cambodia","CashOut":"Y","BankOut":"","MMT":null}
];
var names = [];
list.forEach(function(el) {
if (el.BankOut === 'Y') {
names.push(el.name)
}
})
I am attempting to replace the values in an array with the correct case sensitivity. This is because I am attempting to correct user inputs. I retrieve the correct casing from a page, and the user will have an array of values, some of which will be incorrect.
Ex:
userValues = ["apple321", "orange_22", "pineApple" , "Cantelope", "grASShopper_9000"];
var value1 = "Apple321";
var value2 = "orange_22";
var value3 = "Cantelope";
var value4 = "GrassHopper_9000";
Then after some function ran through all the values, the result would be:
userValues = ["Apple321", "orange_22", "pineApple" , "Cantelope", "GrassHopper_9000"];
The reason I have value1, value2, etc is because I've already created a loop to run through an object. Just not sure how to compare the resulting values. Here is what I have already however:
// When the user enters data, it's sometimes case insensitive. This normalizes the data.
function NormalizeData(downloaded_data)
{
$.each(downloaded_data, function(website,streams){
$.each(streams, function(stream_name,value){
stream_list[website] // This is the global variable array
value.displayName; // This is the value I need to check case sensitivity, and replace with the new case if different
});
});
}
Here is the requested data structure:
downloaded_data = {
twitch_tv : {
timthetatman : {
Online: "1",
Website: "twitch_tv",
displayName: "TimTheTatman"
}
}
}
streamlist = {
twitch_tv : {
["timthetatman"]
}
hitbox_tv: {
[]
}
}
I figured it out. Since I am using an array for the values I want to change, and not an object, it's actually much simpler than I thought. I ran a loop on every value, and if the lowercase of both values matched, but the non-lowercase values didn't, I replaced it in the array, using the numerical key as a reference.
function NormalizeData(downloaded_data)
{
$.each(downloaded_data, function(website,streams){
$.each(streams, function(stream_name,value){
$.each(stream_list[website], function(arrKey,arrVal){
if(arrVal.toLowerCase() == stream_name.toLowerCase() && stream_list[website][arrKey] !== value.displayName)
stream_list[website][arrKey] = value.displayName;
});
});
});
}
Here it is, simplified, if the array is called Array1 and the value Value1:
var Array1 = ["apple"];
var Value1 = ["Apple"];
$.each(Array1, function(arrKey,arrVal){
if(arrVal.toLowerCase() == Value1.toLowerCase() && arrVal !== Value1)
Array1[arrKey] = Value1;
});