1

After finding out that sorting objects is not possible - even though I need the values of the objects sorted - I believe that I have to push the content of the object array to an array for sorting.

My code below produces this output without implementing any send to an array function:

enter image description here

This is my code:

var aveArr = {};
var length = 0;
var q = d3.queue();
['csv goes here', 'another csv goes here'].map((c) => {
  q.defer(d3.csv, c);
  length += 1;
});

q.awaitAll(function(d, csvs){
    var selection = d3.merge(csvs);

    selection.map((d,i) => {
      aveArr[d.word] = {
        sum: 0,
        average: 0,
    };  

    var obj = aveArr[d.word];
    obj.sum += +d.frequency;
    obj.average = obj.sum / length;
});

  console.log(aveArr); 

});

I only need the word and average to be displayed in the console, then for the averages to be sorted.

I've found this for pushing content to arrays, but for me, it doesn't work.

3
  • are you trying to sort objects based on their average? are the objects in an array? Commented Sep 10, 2018 at 7:23
  • @ChrisLi Yep, just the objects based on the average. And the objects are in an array. Is there a better way to sum the values in the CSV files and average them than the way I'm doing at the moment? Commented Sep 10, 2018 at 7:29
  • i dont know how to work with csv files, but sorting an array of object should be simple, just use .sort() Commented Sep 10, 2018 at 7:36

2 Answers 2

2

At the moment you're using the 'array' as an object by setting keys on it. I would advice to change the data structure so it's a real array with fixed fields. Then sorting and transforming becomes very easy:

//	source data
const data = [
  { name: "0", sum: 0, average: 0 },
  { name: "001", sum: 0, average: 0 },
  { name: "00", sum: 1, average: 0.5 },
  { name: "01", sum: 0, average: 0 },
  { name: "1", sum: 11, average: 5.5 },
  { name: "1am", sum: 0, average: 0 },
  { name: "1pickford", sum: 0, average: 0 },
  { name: "1pm", sum: 0, average: 0 },
  { name: "1pm2", sum: 0, average: 0 },
  { name: "1st", sum: 3, average: 1.5 },
  { name: "1x", sum: 2, average: 1 },
  { name: "1xbet", sum: 0, average: 0 }
];
const transformed = data
  //	we only want the name and average
  .map(({ name, sum, average }) => ({ name, average }))
  //	sort by average
  .sort(( a, b ) => a.average - b.average );

console.log( transformed );

Sign up to request clarification or add additional context in comments.

5 Comments

At what point should I restructure the data? After I calculate the average?
Hmm, I'm getting aveArr.map is not function... I'm replacing the data in your snippet with aveArr
You are omitting sum in your example. Maybe that data is still required. Also, in OP's question the data structure is an object, not an array.
1) That's what the OP asked for. That we only have the word and the average to log to the console, hence I include the mapping. Since I'm using constants, the original can still be logged instead when the sum needs to be included. 2) My point is exactly that if the OP would use an array to represent the collection and a name field on the items of that collection, all transformations become shorter and less convoluted. It's easily the best technique I've ever learned on Stack Overflow.
Also, as per the javascript spec, the order of properties on an object is not guaranteed. So anything involving sorting will automatically require you to cast the object to an array or a map to 100% guarantee the order of things stays the same after the sorting finishes. Since the OP creates the object themselves, why not use an array to begin with?
1

Do you want to keep your object structure?

const aveArr = {
  '0': { sum: 0, average: 0 },
  '001': { sum: 0, average: 0 },
  '00': { sum: 1, average: 0.5 },
  '01': { sum: 0, average: 0 },
  '1': { sum: 11, average: 5.5 },
  '1am': { sum: 0, average: 0 },
  '1pickford': { sum: 0, average: 0 },
  '1pm': { sum: 0, average: 0 },
  '1pm': { sum: 0, average: 0 },
  '1st': { sum: 3, average: 1.5 },
  '1x': { sum: 2, average: 1 },
  '1xbet': { sum: 0, average: 0 }
};

const transformed = Object
  .keys(aveArr).map(key => ({ name: key, average: aveArr[key].average }));
  
const sorted = transformed.sort((left, right) => left.average - right.average);

console.log(sorted);

2 Comments

I like this approach, can you explain the first line of code?I don't understand ({name: key, ...aveArry[key]})
aveArr[key] will equal to an object out of your array. Using the spread operator will merge all properties from that object into your newly created object { name: }.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.