Destructure inside sort method javascript - javascript

I wrote a module that has sorting methods. I also tried to make it more flexible and destructure parameters to sort anything i will set creating object (more or less) but I don't know how to do it inside the sort method. What i tried is in the equal2 last method, but obviesly is not working fine. Does anyone have clue what should i correct in this example?
let products = [ { name: "Grejpfrut", calories: 170, color: "czerwony", sold: 8200 },
{ name: "Pomarańcza", calories: 160, color: "pomarańczowy", sold: 12101 },
{ name: "Cola", calories: 210, color: "karmelowy", sold: 25412 },
{ name: "Cola dietetyczna", calories: 0, color: "karmelowy", sold: 43922 },
{ name: "Cytryna", calories: 200, color: "bezbarwny", sold: 14983 },
{ name: "Malina", calories: 180, color: "różowy", sold: 8200 },
{ name: "Piwo korzenne", calories: 200, color: "karmelowy", sold: 9909 },
{ name: "Woda", calories: 0, color: "bezbarwny", sold: 62123 }
];
class compareSold {
constructor(param1, param2) {
this.param1 = param1 ;
this.param2 = param2 ;
// this.products = products ;
const { calories, sold } = products;
this.sortType = {
asc: (param1, param2) => {
// console.log(param1);
if (param1.sold > param2.sold) {
return 1
} else if (param1.sold === param2.sold) {
return 0
} else {
return -1
}
},
dsc: (param1, param2) => {
// console.log(param1);
if (param2.sold > param1.sold) {
return 1
} else if (param1.sold === param2.sold) {
return 0
} else {
return -1
}
},
eqal: (param1, param2) => {
// console.log(param1);
if (param1.calories > param2.calories) {
return 1
} else if (param1.calories === param2.calories) {
console.log('a wowowiwa !!!');
} else {
return -1
}
},
eqal2: (param1, param2) => {
console.log(param1);
if (param1.sold > param2.sold) {
return 1
} else if ({sold} === {sold}) {
console.log('a wowowiwa !!!');
} else {
return -1
}
}
}
}
}
const { calories, sold } = products; const compareSoldASCPass = new
compareSold();
// function calories ({calories}) { console.log(calories)}; //
// Type of sorting(asc, dsc) ////////////////////////////////////////
const compareSoldASC =
products.sort(compareSoldASCPass.sortType.eqal2)
// console.log(compareSoldASC);
module.exports = compareSoldASC;

Related

JS: append array of objects with data from another

I've got some JS data holding all kinds of data, numbers, child objects, arrays, etc in all manner of different structures:
let datapile = {
cover_img: { uid:'u2a3j4' },
avatar_img: { uid:'u5j3vg' },
created: 8273736384,
friends: [
{ name:'John', img: { uid:'u2726b' }, },
{ name:'Jane', parent: { profile_img: { uid:'u293k4' }, } },
],
occupation: {
past: current,
prior: {
title: 'Accountant',
company: {
logo: { img: { uid:'u29374' } },
}
},
},
...
}
And then I've got this JS list of images:
let imgs : [
{ uid:'u2a3j4', format:'jpg', alt_txt:'Lorem...', size:583729, dominant_color:'#d79273' },
{ uid:'u5j3vg', format:'png', alt_txt:'Lorem...', size:284849, dominant_color:'#f99383' },
{ uid:'u2726b', format:'gif', alt_txt:'Lorem...', size:293742, dominant_color:'#349a83' },
...
],
Now, what I need is a function I can call that will look through the datapile and append img data objects from the imgs list below. So where the datapile now has only the uid reference, it should have the entire img object. And I will then do the same with all kinds of other pieces of referenced data.
I've tried the following function:
function isArray(x){ return ( x !== undefined && Array.isArray(x) ) }
function isObject(x){ return (x && typeof x === "object" && !Array.isArray(x)) }
function get_item(type, uid) { /* loops through eg. imgs and returns img matching uid */ }
function append_referenced_relations(data){
if( !data ) return data
if( isObject(data) && data['uid'] !== undefined ) {
let item = get_item('any', data['uid'])
data = item
}
if( isObject(data) || isArray(data) ) {
for( let key in data ) {
data[key] = this.append_referenced_relations(deepClone(data[key]))
}
}
return data
}
... but I just can't get it to work. And my best googling efforts for similar scenarios have also come up empty. Can the internet help me out here?
you can try something like this
basically it use recursion and Object.fromEntries /entries to check all the keys of the inner object
if you have any specific question feel free to ask me
const decorate = (obj, data) => {
if (typeof obj !== 'object') {
return obj
}
if (Array.isArray(obj)) {
return obj.map(e => decorate(e, data))
}
return Object.fromEntries(
Object.entries(obj).flatMap(([k, v]) => {
if (k === 'uid') {
const imgData = data.find(d => v === d.uid)
return Object.entries(imgData || [[k, v]])
}
return [
[k, decorate(v, data)]
]
})
)
}
let datapile = {
cover_img: {
uid: 'u2a3j4'
},
avatar_img: {
uid: 'u5j3vg'
},
created: 8273736384,
friends: [{
name: 'John',
img: {
uid: 'u2726b'
},
},
{
name: 'Jane',
parent: {
profile_img: {
uid: 'u293k4'
},
}
},
],
occupation: {
past: 'current',
prior: {
title: 'Accountant',
company: {
logo: {
img: {
uid: 'u29374'
}
}
}
}
}
}
let imgs = [{
uid: 'u2a3j4',
format: 'jpg',
alt_txt: 'Lorem...',
size: 583729,
dominant_color: '#d79273'
},
{
uid: 'u5j3vg',
format: 'png',
alt_txt: 'Lorem...',
size: 284849,
dominant_color: '#f99383'
},
{
uid: 'u2726b',
format: 'gif',
alt_txt: 'Lorem...',
size: 293742,
dominant_color: '#349a83'
}
]
console.log(decorate(datapile, imgs))
You need to recurse in the nested datapile to identify the object with uids and add the img properties to be added.
Few cases to consider:
Objects. (If the Object has uid property, then stop recursion for its properties)
Object values having objects.
Array of Objects.
No need to return anywhere in your function actually as we can update objects inline.
Try like below.
let imgs = [ { uid: "u2a3j4", format: "jpg", alt_txt: "Lorem...", size: 583729, dominant_color: "#d79273", }, { uid: "u5j3vg", format: "png", alt_txt: "Lorem...", size: 284849, dominant_color: "#f99383", }, { uid: "u2726b", format: "gif", alt_txt: "Lorem...", size: 293742, dominant_color: "#349a83", }, { uid: "u293k4", format: "gif", alt_txt: "Lorem...", size: 193742, dominant_color: "#349a83", }, { uid: "u29374", format: "gif", alt_txt: "Lorem...", size: 793742, dominant_color: "#349a83", }, ]; let datapile = { cover_img: { uid: "u2a3j4" }, avatar_img: { uid: "u5j3vg" }, created: 8273736384, friends: [ { name: "John", img: { uid: "u2726b" } }, { name: "Jane", parent: { profile_img: { uid: "u293k4" } } }, ], occupation: { past: "current", prior: { title: "Accountant", company: { logo: { img: { uid: "u29374" } }, }, }, }, };
function isArray(x) {
return x !== undefined && Array.isArray(x);
}
function isObject(x) {
return typeof x === "object" && !Array.isArray(x);
}
function get_item(uid) {
return imgs.find((img) => img.uid === uid);
}
function append_referenced_relations(data) {
if (isObject(data)) {
if (data["uid"] !== undefined) {
const img = get_item(data.uid);
// Add img properties to the same object as properties
Object.entries(img).forEach(([key, value]) => {
data[key] = value;
});
} else {
// Recurse for the object values
Object.values(data).forEach((item) => {
append_referenced_relations(item);
});
}
} else if (isArray(data)) {
data.forEach((item) => {
// Recurse for the array entries
append_referenced_relations(item);
});
}
}
append_referenced_relations(datapile);
console.log(JSON.stringify(datapile, null, 2));

Javascript code reduction on sort with multiple fields

I have an array with data similar to this but with more fields to sort from:
const shirts= [
{
type: "T-shirt",
size: "L",
color: "Black",
},
{
type: "Dress Shirt",
size: "S",
color: "Brown",
},
{
type: "Sweatshirt",
size: "M",
color: "Red",
},
{
type: "Polo",
size: "XS",
color: "Pink",
},
...]
I have a sort function that works differently based on what is selected, for example if the user sorts by size it needs to go from XS to XL but any other option it needs to sort alphabetically. This is what I have:
//sort is the option the user decided to sort by
SortedShirts(sort,shirts){
var newShirtArray=[];
var size1=0;
var size2=0;
if(sort === "type"){
newShirtArray= shirts.sort(function(shirt1,shirt2){
if (shirt1.type> shirt2.type){
return 1;
}
else{
return -1;
}
});
}
else if(sort === "color"){
newShirtArray = shirts.sort(function(shirt1,shirt2){
if (shirt1.color > shirt2.color){
return 1;
}
else{
return -1;
}
});
}
else if(sort === "size"){
newShirtArray = shirts.sort(function(shirt1,shirt2){
if(shirt1.size==="XS"){
size1=0;
}
else if(shirt1.size==="S"){
size1=1;
}
else if(shirt1.size==="M"){
size1=2;
}
else if(shirt1.size==="L"){
size1=3;
}
else if(shirt1.size==="XL"){
size1=4;
}
if(shirt2.size==="XS"){
size2=0;
}
else if(shirt2.size==="S"){
size2=1;
}
else if(shirt2.size==="M"){
size2=2;
}
else if(shirt2.size==="L"){
size2=3;
}
else if(shirt2.size==="XL"){
size2=4;
}
if (size1 > size2){
return 1;
}
else{
return -1;
}
});
}
This seems repetitive to me because type and color sort the same way just with a different field and I feel I can put that into one sort but I am unsure on how to do it. I'm wondering if there is something like this
if(sort === "type" || sort === "color"){
newShirtArray= shirts.sort(function(shirt1,shirt2){
if (shirt1.fieldOf(sort) > shirt2.fieldOf(sort)){
return 1;
}
else{
return -1;
}
});
}
Or another way to reduce my code?
You can use a switch statement:
switch (sort) {
case 'color':
case 'type':
newShirtArray = shirts.sort(/* ... */);
break;
case 'size':
newShirtArray = shirts.sort(/* ... */);
break;
}
For converting you shirt size to number, you can use an object:
const ShirtSizes = {
XS: 0, S: 1, M: 2, L: 3, XL: 4,
};
const shirt1Size = ShirtSizes[shirt1.size];
If your environment allows this, use more concise ES2015 arrow functions:
case 'size':
newShirtArray = shirts.sort((s1, s2) => ShirtSizes[s1.size] - ShirtSizes[s2.size]);
break;
For type and color, as you guessed, you can use this:
case 'color':
case 'type':
newShirtArray = shirts.sort((s1, s2) => {
if (s1[sort] > s2[sort]) {
return 1;
} else if (s1[sort] < s2[sort]) {
return -1;
} else {
return 0;
}
});
I hope this will help a bit.
You can access JSON object's key using bracket.
const shirts = [
{
type: "T-shirt",
size: "L",
color: "Black",
},
{
type: "Dress Shirt",
size: "S",
color: "Brown",
},
{
type: "Sweatshirt",
size: "M",
color: "Red",
},
{
type: "Polo",
size: "XS",
color: "Pink",
},
]
function SortedShirts(sort, shirts) {
var newShirtArray = [];
var size1 = 0;
var size2 = 0;
if (sort === "type" || sort === "color") {
newShirtArray = shirts.sort(function (shirt1, shirt2) {
if (shirt1[sort] > shirt2[sort]) {
return 1;
}
else {
return -1;
}
});
}
else if (sort === "size") {
const sizes = ['XS', 'S', 'M', 'L', 'XL']
newShirtArray = shirts.sort(function (shirt1, shirt2) {
const size1 = sizes.indexOf(shirt1.size)
const size2 = sizes.indexOf(shirt2.size)
if (size1 > size2) {
return 1;
}
else {
return -1;
}
});
}
}

Why is this recursive function overwriting the values of the second call?

Sorry for the title, I'm not even sure how to phrase what is happening here.
I'm working on an expense tracking program in React that supports multiple currencies. The expenses being tracked can be nested arbitrarily deep in a JSON object.
entertainment: {
_values: {
USD: 23,
AUD: 5,
},
'food & drink': {
_values: {
AUD: 83,
},
'local bar': {
_values: {
AUD: 28,
USD: 2,
},
},
},
minigolf: {
_values: {
USD: 112,
},
}
}
An expense can have an amount stored directly in it, but it can also act as a 'parent' category to further detailed sub-expenses.
To display the total value of an expense I've written a pair of functions:
sumValues(values)
Sums up an array of _values objects (a value object is a key-value store of currency codes and integers)
totalExpense(expense)
Returns the total value of an expense. ie any _values it has, + the totalExpense of any children expenses.
I thought I'd written these as pure functions, but when calling totalExpense() recursively the first child of an expense returns the wrong total.
totalExpense(entertainment);
//-> Object { USD: 137, AUD: 116 }
OK
totalExpense(entertainment['food & drink']);
//-> Object { AUD: 111, USD: 2 }
OK
totalExpense(entertainment);
totalExpense(entertainment['food & drink']);
//-> Object { AUD: 139, USD: 4 }
NOT OK
I've been poking at this code for hours now, but for the life of me can't see what is happening:
sumValues = values => {
return values.reduce((acc, cur) => {
for (const currency in cur) {
acc[currency]
? (acc[currency] = acc[currency] + cur[currency])
: (acc[currency] = cur[currency]);
}
return acc;
});
};
totalExpense = expense => {
const values = [];
if (expense['_values']) {
values.push(expense['_values']);
}
const subExpenses = Object.keys(expense).filter(child => {
return child[0] !== '_';
});
if (subExpenses.length > 0) {
for (const subExpense of subExpenses) {
let subtotal = this.totalExpense(expense[subExpense]);
values.push(subtotal);
}
}
if (values.length) {
return this.sumValues(values);
} else {
throw Error('No values in this expense');
}
};
render() {
const entertainment = {
_values: {
USD: 23,
AUD: 5,
},
'food & drink': {
_values: {
AUD: 83,
},
'local bar': {
_values: {
AUD: 28,
USD: 2,
},
},
},
minigolf: {
_values: {
USD: 112,
},
},
};
console.log(this.totalExpense(entertainment));
console.log(this.totalExpense(entertainment['food & drink']));
console.log(this.totalExpense(entertainment['minigolf']));
return;
}
The problem is that your reduce callback's initial value is the first item in the values array, and then you proceed to assign to that item:
acc[currency]
? (acc[currency] = acc[currency] + cur[currency])
: (acc[currency] = cur[currency]);
So, the first item gets mutated every time sumValues is called. Instead, provide an empty object as the initial value for the reduce:
sumValues = values => {
return values.reduce((acc, cur) => {
for (const currency in cur) {
acc[currency]
? (acc[currency] = acc[currency] + cur[currency])
: (acc[currency] = cur[currency]);
}
return acc;
}, {});
};
sumValues = values => {
return values.reduce((acc, cur) => {
for (const currency in cur) {
acc[currency] ?
(acc[currency] = acc[currency] + cur[currency]) :
(acc[currency] = cur[currency]);
}
return acc;
}, {});
};
totalExpense = expense => {
const values = [];
if (expense['_values']) {
values.push(expense['_values']);
}
const subExpenses = Object.keys(expense).filter(child => {
return child[0] !== '_';
});
if (subExpenses.length > 0) {
for (const subExpense of subExpenses) {
let subtotal = this.totalExpense(expense[subExpense]);
values.push(subtotal);
}
}
if (values.length) {
return this.sumValues(values);
} else {
throw Error('No values in this expense');
}
};
const entertainment = {
_values: {
USD: 23,
AUD: 5,
},
'food & drink': {
_values: {
AUD: 83,
},
'local bar': {
_values: {
AUD: 28,
USD: 2,
},
},
},
minigolf: {
_values: {
USD: 112,
},
},
};
console.log(totalExpense(entertainment));
console.log(totalExpense(entertainment['food & drink']));

Vue.js Asynchronous Traversing

Open the page, get sexList and clientList form the server
Traverse 2 sets of data, push the sexText into the clientList
But the code is not working. How can I modify my code?
Code is here:
let sexList = [// store data: sexList
{
code: 0,
sexText: 'female',
},
{
code: 1,
sexText: 'male',
}
]
let clientList = [// index data: clientList
{
name: 'john',
sexCode: 1,
},
{
name: 'joe',
sexCode: 0,
}
]
mounted() {
this.$store.dispatch('getSexList')// get sexList form the server
getClientList({data: 'clients'}).then((res) => {
if(res.data.success) {
this.clientList = res.data.data// get clientList form the server
}else {
this.$message.error(res.data.message)
}
}).catch((err) => {
console.log(err)
})
},
watch: {
/*
watch clientList,traversing cientList and sexList,push the sexText into the clientList
*/
clientList(val) {
if(val && val.length > 0) {
val.map((item) {
this.$store.getters.sexList.map((sex_item) => {
if(sex_item.sexCode == item.sexCode) {
item.sexText = sex_item.sexText
}
})
})
}
},
}
After edit, it is working
setTimeout(() => {
getClientList({data: 'clients'}).then((res) => {
if(res.data.success) {
this.clientList = res.data.data// get clientList form the server
}else {
this.$message.error(res.data.message)
}
}).catch((err) => {
console.log(err)
})
}, 1000)
let clientList = [// index data: clientList
{
name: 'john',
sexCode: 1,
sexText: 'male',
},
{
name: 'joe',
sexCode: 0,
sexText: 'female',
}
]
Have another way?

(javascript) There seem to be two things wrong with this code

Do I need to execute a bind(this) somewhere and the console log placement seems to be off?
var company = {
employees: [{
name: "doug"
},
{
name: "AJ"
}
],
getName: function(employee) {
return employee.name
},
getNames: function() {
return this.employees.map(this.getName)
},
delayedGetNames: function() {
setTimeout(this.getNames, 500)
}
}
console.log(company.delayedGetNames());
setTimeout(this.getNames.bind(this), 500)
^
|
+----< HERE
var company = {
employees: [{
name: "doug"
},
{
name: "AJ"
}
],
getName: function(employee) {
return employee.name
},
getNames: function() {
return this.employees.map(this.getName)
},
delayedGetNames: function() {
var fn = function() {
var names = this.getNames();
console.log(names);
};
setTimeout(fn.bind(this), 500);
}
}
company.delayedGetNames();

Categories

Resources