This question already has answers here:
Javascript - Counting duplicates in object array and storing the count as a new object
(3 answers)
Closed 3 years ago.
What's the best way to get duplicates in an array of hashes with strings and count number of appearances.
If I have this array of hashes
const data = [
{
url: 'https://app.mywebsite.net/endpoint1',
method: 'POST'
},
{
url: 'https://app.mywebsite.net/endpoint2',
method: 'POST'
},
{
url: 'https://app.mywebsite.net/endpoint1',
method: 'POST'
}
]
And I want to get the hashes that are duplicated and the amount of times they appear like
{
url: 'https://app.mywebsite.net/endpoint1',
method: 'POST',
count: 2
},
{
url: 'https://app.mywebsite.net/endpoint2',
method: 'POST',
count: 1
},
Javascript - Counting duplicates in object array and storing the count as a new object
You can use Array.reduce for that :
const data = [
{
url: "https://app.mywebsite.net/endpoint1",
method: "POST"
},
{
url: "https://app.mywebsite.net/endpoint2",
method: "POST"
},
{
url: "https://app.mywebsite.net/endpoint1",
method: "POST"
}
];
const result = data.reduce((all, curr) => {
const ndx = all.findIndex(e => e.url === curr.url);
if (ndx > -1) {
all[ndx].count += 1;
} else {
all.push({ url: curr.url, count: 1 });
}
return all;
}, []);
console.log(result)
Like #Taki mentions, you can use the Array.prototype.reduce() method.
const frequencies = arr =>
Object.values(
arr.reduce((obj, { url, method }) => {
obj[url] = obj[url] || { url, method, count: 0 }
obj[url].count += 1
return obj
}, {})
)
const data = [
{
url: 'https://app.mywebsite.net/endpoint1',
method: 'POST',
},
{
url: 'https://app.mywebsite.net/endpoint2',
method: 'POST',
},
{
url: 'https://app.mywebsite.net/endpoint1',
method: 'POST',
},
]
const result = frequencies(data)
console.log(result)
Using with reduce (or forEach) will simplify.
const data = [
{
url: "https://app.mywebsite.net/endpoint1",
method: "POST"
},
{
url: "https://app.mywebsite.net/endpoint2",
method: "POST"
},
{
url: "https://app.mywebsite.net/endpoint1",
method: "POST"
}
];
const updated = data.reduce(
(acc, curr) =>
Object.assign(acc, {
[curr.url]:
curr.url in acc
? { ...acc[curr.url], count: acc[curr.url].count + 1 }
: { ...curr, count: 1 }
}),
{}
);
console.log(updated);
Related
This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 1 year ago.
I am trying to create an array of User IDs to send in an AJAX Post Request. I can get the User IDs okay and display them individually in console.log but after I push them to the connectionData array and try to do a console.log on specific indices I get undefined, also when I try console.log(connectionData.length) it returns 0. I believe this is a sync issue but I can't figure out how to solve it, I have read similar posts and they aren't helping.
const prepareUserDataForConnection = function(){
var connectionData = [];
var currentUser = 'robert';
var currentUser = 'chris';
console.log(currentUser);
console.log(followedUser);
$.ajax({
type: 'GET',
url: '/api/currentuserinfo/',
data: {
'current_user': currentUser
},
success: function(data) {
let currentUserId = JSON.stringify(data[0].id);
console.log('Current User Pk is: ' + currentUserId);
connectionData.push(currentUserId);
},
});
$.ajax({
type: 'GET',
url: '/api/followeduserinfo/',
data: {
'followed_user': followedUser
},
success: function(data) {
let followedUserId = JSON.stringify(data[0].id);
console.log('Followed User Pk is: ' + followedUserId);
connectionData.push(followedUserId);
},
});
console.log(connectionData)
console.log(connectionData[0])
console.log("Array length is: " + connectionData.length)
};
Here is a screenshot of the problem:
Try this approach with Promise
function ajaxPromise(obj) {
return new Promise(function (resolve, reject) {
obj.success = resolve;
obj.error = reject;
$.ajax(obj);
});
}
const prepareUserDataForConnection = function () {
var currentUser = 'robert';
var followedUser = 'chris';
return Promise.all([
ajaxPromise({
type: 'GET',
url: '/api/currentuserinfo/',
data: { 'current_user': currentUser }
}),
ajaxPromise({
type: 'GET',
url: '/api/followeduserinfo/',
data: { 'followed_user': followedUser }
})
]);
};
prepareUserDataForConnection().then(function (connectionData) {
console.log(connectionData)
console.log(connectionData[0])
console.log("Array length is: " + connectionData.length)
// Write your logic here with connectionData
}).catch(function (error) {
console.log(error);
});
I've this type of array in JS:
[{
websitetype: "onepager"
}, {
layout: "provided"
}, {
layout_provided: "wireframes"
}, {
languages: "single"
}, {
client_name: "dasda"
}, {
client_email: "asdasd#asdasd.fr"
}, {
client_conditions: "on"
}, {
client_newsletter: "on"
}]
How can I send it through Ajax ?
What I tried is:
$.ajax({
type: 'POST',
url: 'assets/send.php',
data: {datas},
success: function(response) { },
});
This is what I would like to get in PHP:
[datas] => Array
(
[websitetype] => onepager
[layout] => provided
[layout_provided] => wireframes
[languages] => single
[client_name] => dasda
[client_email] => asdasd#asdasd.fr
[client_conditions] => on
[client_newsletter] => on
)
What I'm missing here please ?
Thanks.
The first thing you should do is reduce that array into an object matching the format you want
const dataObject = Object.fromEntries(datas.flatMap(o => Object.entries(o)))
This looks like the following
{
"websitetype": "onepager",
"layout": "provided",
"layout_provided": "wireframes",
"languages": "single",
"client_name": "dasda",
"client_email": "asdasd#asdasd.fr",
"client_conditions": "on",
"client_newsletter": "on"
}
You then have two options for posting it to PHP
Send it as raw JSON
$.ajax({
method: "POST",
url: "assets/send.php",
contentType: "application/json",
data: JSON.stringify(dataObject),
processData: false
})
Then read and parse the JSON in PHP
$datas = json_decode(file_get_contents("php://input"), true);
// example
echo $datas["websitetype"]; // "onepager"
Alternatively, let jQuery format the data as an associative PHP array
$.ajax({
method: "POST",
url: "assets/send.php",
data: {
datas: dataObject
}
})
This will post an application/x-www-form-urlencoded request body of
datas%5Bwebsitetype%5D=onepager&datas%5Blayout%5D=provided&datas%5Blayout_provided%5D=wireframes&datas%5Blanguages%5D=single&datas%5Bclient_name%5D=dasda&datas%5Bclient_email%5D=asdasd%40asdasd.fr&datas%5Bclient_conditions%5D=on&datas%5Bclient_newsletter%5D=on
PHP can read this as an array via $_POST
print_r($_POST['datas']);
Results in
Array
(
[websitetype] => onepager
[layout] => provided
[layout_provided] => wireframes
[languages] => single
[client_name] => dasda
[client_email] => asdasd#asdasd.fr
[client_conditions] => on
[client_newsletter] => on
)
Encode your data string into JSON.
const datas = [{
websitetype: "onepager"
}, {
layout: "provided"
}, {
layout_provided: "wireframes"
}, {
languages: "single"
}, {
client_name: "dasda"
}, {
client_email: "asdasd#asdasd.fr"
}, {
client_conditions: "on"
}, {
client_newsletter: "on"
}]
const jsonString = JSON.stringify(datas)
$.ajax({
type: 'POST',
url: 'assets/send.php',
data: { datas: jsonString },
success: function(response) { },
});
In your PHP:
$data = json_decode(stripslashes($_POST['datas']));
// here i would like use foreach:
foreach($datas as $data){
echo $data;
}
I been trying to pass the array of objects to JsonResult action method created on Controller class, I tried all possible solution from different answer but none work.
Here is my js function:
function CalculateCost() {
var distancecost = [];
//prepare the List<DistanceCost> object
for (i = 0; i < _SELECTED_POINTS.length; i++) {
console.log('point::' + _SELECTED_POINTS[i]);
let dist = {
PlaceId: _SELECTED_POINTS[i].place_id,
PointSequence: _SELECTED_POINTS[i].PointSequence,
controlId: _SELECTED_POINTS[i].controlId,
FromLatitude: (i == (_SELECTED_POINTS.length - 1)) ? _SELECTED_POINTS[0].geometry.location.lat() : _SELECTED_POINTS[i].geometry.location.lat(),
FromLongitude: (i == (_SELECTED_POINTS.length - 1)) ? _SELECTED_POINTS[0].geometry.location.lng() : _SELECTED_POINTS[i].geometry.location.lng(),
ToLatitude: _SELECTED_POINTS[i].geometry.location.lat(),
ToLongitude: _SELECTED_POINTS[i].geometry.location.lng(),
DistanceType: 'Mile',
DistanceCalculateType: (i == (_SELECTED_POINTS.length - 1)) ? 'TotalDistance' : 'PickDrop',
TotalPrice: '0',
TotalDistance: '0'
};
console.log(dist);
distancecost.push({
dist
});
}
$.ajax({
method: 'GET',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
url: '/Dashboard/CalculateDistanceAndPrice',
data: JSON.parse(JSON.stringify({ 'distanceCost': distancecost })),
success: function (response) {
console.log('DistanceCalculation Response:: ' + JSON.stringify(response));
},
error: function (response) {
console.log(response);
}
});
}
Here is the Jsonresult action method:
Edit:
As Nicholas suggested, I change the type but still its not working, AFAIK POST we use when we are inserting any data and PUT when updating any data but here I'm just fetching the data by calculating the distance between each point:
$.ajax({
method: 'POST',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
url: '/Dashboard/CalculateDistanceAndPrice',
data: JSON.stringify({ 'distanceCost': distancecost }),
success: function (response) {
console.log('DistanceCalculation Response:: ' + JSON.stringify(response));
},
error: function (response) {
console.log(response);
}
});
Edit:
I changed the object creation but still no luck:
var DistanceCost = new Object();
DistanceCost.PlaceId = _SELECTED_POINTS[i].place_id;
DistanceCost.PointSequence = _SELECTED_POINTS[i].PointSequence;
DistanceCost.controlId = "";//_SELECTED_POINTS[i].controlId,
DistanceCost.FromLatitude = (i == (_SELECTED_POINTS.length - 1)) ? _SELECTED_POINTS[0].geometry.location.lat() : _SELECTED_POINTS[i].geometry.location.lat();
DistanceCost.FromLongitude = (i == (_SELECTED_POINTS.length - 1)) ? _SELECTED_POINTS[0].geometry.location.lng() : _SELECTED_POINTS[i].geometry.location.lng();
DistanceCost.ToLatitude = _SELECTED_POINTS[i].geometry.location.lat();
DistanceCost.ToLongitude = _SELECTED_POINTS[i].geometry.location.lng();
DistanceCost.DistanceType = 'Mile';
DistanceCost.DistanceCalculateType = (i == (_SELECTED_POINTS.length - 1)) ? 'TotalDistance' : 'PickDrop';
DistanceCost.TotalPrice = '0';
DistanceCost.TotalDistance = '0';
try to remove quotations of distanceCost
+> data: JSON.parse(JSON.stringify({ distanceCost: distancecost }))
Can someone help me with this, I am trying to achieve an object like so:
{ "docs": [
{ "_id": "item" },
{ "_id": "item" },
{ "_id": "item" }
] }
So I begin with having an object with a key docs which is an array I will push into
let query = { docs: [] };
i then have list of key value pair items like so, around 80:
{ _id: item }
which i push into docs in a forEach loop
query.docs.push(item);
So when I go and stringify
JSON.stringify(query);
it returns the object but the array is empty.
{ "docs": [] }
I’ve no idea why this is happening. Anyone know an approach to go around this to achieve the desired result? Thanks in advance
Actual code:
let elasticQuery = {
docs: []
};
axios({
method: "post",
headers: {
"Content-Type": "application/json"
},
url: sent2VecUrl,
data: {
selected_text: query
}
}).then(results => {
results.data.response.forEach(item => {
elasticQuery.docs.push({ _id: item });
});
});
console.log("without: " + elasticQuery + " with stringify :" + JSON.stringify(elasticQuery));
This is the server response:
Move your console in .then function. This is asyn call and your console is printing before your promise is getting resolved.
axios({
method: "post",
headers: {
"Content-Type": "application/json"
},
url: sent2VecUrl,
data: {
selected_text: query
}})
.then(results => {
results.data.response.forEach(item => {
elasticQuery.docs.push({ _id: item });
});
console.log("without: " + elasticQuery + " with stringify :" + JSON.stringify(elasticQuery));
});
You code looks fine.
.then(results => {
results.data.response.forEach(item => {
elasticQuery.docs.push({ _id: item });
});
console.log(elasticQuery);
});
instead of this:
results.data.response.forEach(item => {
elasticQuery.docs.push({ _id: item });
});
do this:
elasticQuery.docs = results.data.response.map(item => ({ _id: item }) )
I have this factory:
angular.module('core.actor').factory('Actor', ['$resource',
function ($resource) {
return $resource('api/actor/:actorId/', {}, {
query: {
method: 'GET',
isArray: true,
cache: true
},
update: {
method: 'PUT'
}
});
}
]);
And this is part of my paging function:
if (self.pk == "-6" && self.searchTerm == undefined) {
self.actorsToAdd = Actor.query({
offset: pageOffset,
limit: pageLimit
})
} else if (self.pk == "-6") {
self.actorsToAdd = Actor.query({
offset: pageOffset,
limit: pageLimit,
search: self.searchTerm
})
} else if (self.searchTerm == undefined) {
self.actorsToAdd = Actor.query({
offset: pageOffset,
limit: pageLimit,
pk: self.pk.toString()
})
} else {
self.actorsToAdd = Actor.query({
offset: pageOffset,
limit: pageLimit,
search: self.searchTerm,
pk: self.pk.toString()
})
}
It changes the GET request generated by Actor depending on certain conditions. I'm looking for a way to parametrize this function so I would be able to replace 'Actor' with a variable.
Something along the lines of:
pageType = Movie;
var page = function (pageType){
self.itemsToAdd = pageType.query({
offset: pageOffset,
limit: pageLimit
})
}
Is it possible? If so, how?
This is how I do it, rather than passing individual parameters into the query, pass in a object, which contains your query parameters.
angular.module('core.actor').factory('Actor', ['$resource',
function ($resource) {
return $resource('api/actor/:actorId/', {}, {
query: {
method: 'GET',
isArray: true,
cache: true,
params: { queryParams: '#_queryParams' }
},
update: {
method: 'PUT'
}
});
}
]);
so your call to it looks like this
Actor.query({ queryParams: {
offset: pageOffset,
limit: pageLimit,
pk: self.pk.toString()
}})
Then on the server I look at which values are contained in my (json parsed) params, in order to construct the appropriate query on the database.
After your latest comment, is this the kind of thing you're looking for?
angular.module('core.actor').factory('Api', ['$resource',
function ($resource) {
return {
actor: $resource('api/actor/:actorId/', {}, {
query: {
method: 'GET',
isArray: true,
cache: true,
params: {queryParams: '#_queryParams'}
},
update: {
method: 'PUT'
}
}),
movie: $resource('api/move/:moveId/', {}, {
query: {
method: 'GET',
isArray: true,
cache: true,
params: {queryParams: '#_queryParams'}
},
update: {
method: 'PUT'
}
})
};
}
]);
You could then call either Api.movie.query() or Api.actor.query()
For completeness, heres how my server side code looks when building my query.
var constructUserQuery = function (queryParams) {
var query = { $or: [], $and: [] };
if (queryParams.name) {
query.$and.push({ displayName: { $regex: queryParams.name, $options: 'i'} });
}
if (queryParams.client) {
query.$or.push({ client: mongoose.Types.ObjectId(queryParams.client) });
}
if (queryParams.roles) {
query.$or.push({ roles: { $in: queryParams.roles }});
}
// Ignore the current user, if it's supplied
if (queryParams.user) {
query.$and.push({ _id: { $ne: queryParams.user._id }});
}
// Clean up any empty arrays
if (query.$or.length === 0) {
delete query.$or;
}
if (query.$and.length === 0) {
delete query.$and;
}
return query;
};
Obviously this is specific to my case but you get the idea. This is the only place where I have any if statements.