Je veux alimenter un graphique linéaire avec un tableau simple [0,1,2, ...] représentant des sommes de amount divisées par jours. Le tableau d'entrée a une structure complexe, donc ma première approche a été la suivante:

const data = [{
    LQsZ2cuD1n5U10Rhg9p: {
      amount: 140,
      timestamp: 1541768493811
    }
  },
  {
    LR6Bx6pih4TRID9i3LW: {
      amount: 240,
      timestamp: 1542014096044
    }
  },
  {
    LR6IbF4Q0SI9TZ6Sh5h: {
      amount: 340,
      timestamp: 1542015841476
    }
  },
  {
    LR6NLdgGd2UgTMpnYYE: {
      amount: 460,
      timestamp: 1542017084204
    }
  },
  {
    LR6R5ql8lJW_gTctXB6: {
      amount: 110,
      timestamp: 1542018068191
    }
  },
  {
    LR6R5v0ag8twyTjeupC: {
      amount: 120,
      timestamp: 1542018068351
    }
  },
  {
    LR6R5xZZ4VNCIud71MP: {
      amount: 160,
      timestamp: 1542018069574
    }
  },
  {
    LR6R5zz5QrvrM_RTrvT: {
      amount: 310,
      timestamp: 1542018069716
    }
  },
  {
    LR6R6Aser7lmvrGetzm: {
      amount: 210,
      timestamp: 1542018069996
    }
  },
]

function getReduced(index) {
  const y = Object.values(data).map(e => Object.values(e))
    .map(e => Object.values(e)[0])
    .map(e => [Math.round((Date.now() - e.timestamp) / 8.64e7), e.amount])
    .filter(e => e[0] === index).map(e => e[1]);
  if (y === undefined) return 0;
  else return y.reduce((a, b) => a + b, 0);
}

const info = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((e, i) => getReduced(i++));
document.getElementById("info").innerHTML = info;

var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
    type: 'line',
    data: {
        labels: ["Today","1 day ago","2 days ago","3 days ago","4 days ago","5 days ago","6 days ago","A week ago","8 days ago","9 days ago","10 days ago","11 days ago",],
        datasets: [{
            label: 'Money earned',
            data: info,
            backgroundColor: [
                'rgba(255, 99, 132, 0.2)',
                'rgba(54, 162, 235, 0.2)',
                'rgba(255, 206, 86, 0.2)',
                'rgba(75, 192, 192, 0.2)',
                'rgba(153, 102, 255, 0.2)',
                'rgba(255, 159, 64, 0.2)',
                'rgba(255, 99, 132, 0.2)',
                'rgba(54, 162, 235, 0.2)',
                'rgba(255, 206, 86, 0.2)',
                'rgba(75, 192, 192, 0.2)',
                'rgba(153, 102, 255, 0.2)'
            ],
            borderColor: [
                'rgba(255,99,132,1)',
                'rgba(54, 162, 235, 1)',
                'rgba(255, 206, 86, 1)',
                'rgba(75, 192, 192, 1)',
                'rgba(153, 102, 255, 1)',
                'rgba(255, 159, 64, 1)',
                'rgba(255,99,132,1)',
                'rgba(54, 162, 235, 1)',
                'rgba(255, 206, 86, 1)',
                'rgba(75, 192, 192, 1)',
                'rgba(153, 102, 255, 1)'
            ],
            borderWidth: 3
        }]
    },
    options: {
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero:true
                }
            }]
        }
    }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.bundle.js"></script>
<div>Final array for feeding my chart: [<span id="info"></span>]</div>
<canvas id="myChart" width="400" height="400"></canvas>

Cela fonctionne un peu, je lutte depuis plusieurs heures déjà, mais je suis sûr qu'il existe un moyen plus intelligent et concis de gérer de telles situations où vous souhaitez trier et additionner rapidement les valeurs du tableau en fonction de vos besoins en temps.
Oui, ce [0,1 ...] final est boiteux comme le diable, faisant cela, j'ai essayé d'exécuter la fonction 11 fois comme mon graphique va pendant les 11 derniers jours (Array (11) n'a pas fonctionné pour une raison quelconque, les valeurs étaient vides).

Aidez-moi à KO ce m * ker laid!

EDIT: avoir ajouté le tableau souhaité pour avoir l'idée. Il pourrait y avoir des jours sans gains. Le graphique affiche toujours les 11 derniers jours, de sorte que la fenêtre temporelle glissera tous les jours, laissant des valeurs non pertinentes hors du graphique.

2
Igniter 19 nov. 2018 à 20:13

5 réponses

Meilleure réponse

Si j'ai bien compris votre question, vous pouvez utiliser un seul reduce comme ceci:

const data = [{ LQsZ2cuD1n5U10Rhg9p: { amount: 14, timestamp: 1541768493811 } }, { LR6Bx6pih4TRID9i3LW: { amount: 24, timestamp: 1542014096044 } }, { LR6IbF4Q0SI9TZ6Sh5h: { amount: 34, timestamp: 1542015841476 } }, { LR6NLdgGd2UgTMpnYYE: { amount: 46, timestamp: 1542017084204 } }, { LR6R5ql8lJW_gTctXB6: { amount: 11, timestamp: 1542018068191 } }, { LR6R5v0ag8twyTjeupC: { amount: 12, timestamp: 1542018068351 } }, { LR6R5xZZ4VNCIud71MP: { amount: 16, timestamp: 1542018069574 } }, { LR6R5zz5QrvrM_RTrvT: { amount: 31, timestamp: 1542018069716 } }, { LR6R6Aser7lmvrGetzm: { amount: 21, timestamp: 1542018069996 } }, ]

const group = arr => arr.reduce((r,c) => {
  let key = Object.keys(c)[0], date = Math.round((Date.now() - c[key].timestamp) / 864e5)
  r[date] += c[key].amount
  return r
}, new Array(11).fill(0))

console.log(group(data)) //(11) [0, 0, 0, 0, 0, 0, 0, 195, 0, 0, 14]

L'idée est de commencer avec un tableau pré-rempli de 0 via new Array(11).fill(0) et de l'utiliser comme accumulator pour la réduction. Puisque la clé date n'affecte que 2 éléments [index 7 et 10], la réduction ne mettra à jour que ceux qui laissent le reste en 0 pour correspondre à la sortie attendue.

0
Akrion 19 nov. 2018 à 19:16

Alternative pour énumérer les valeurs lors de l'analyse:

const json = '[{"LQsZ2cuD1n5U10Rhg9p":{"amount":140,"timestamp":1541768493811}},{"LR6Bx6pih4TRID9i3LW":{"amount":240,"timestamp":1542014096044}},{"LR6IbF4Q0SI9TZ6Sh5h":{"amount":340,"timestamp":1542015841476}},{"LR6NLdgGd2UgTMpnYYE":{"amount":460,"timestamp":1542017084204}},{"LR6R5ql8lJW_gTctXB6":{"amount":110,"timestamp":1542018068191}},{"LR6R5v0ag8twyTjeupC":{"amount":120,"timestamp":1542018068351}},{"LR6R5xZZ4VNCIud71MP":{"amount":160,"timestamp":1542018069574}},{"LR6R5zz5QrvrM_RTrvT":{"amount":310,"timestamp":1542018069716}},{"LR6R6Aser7lmvrGetzm":{"amount":210,"timestamp":1542018069996}}]'
const info = Array(11).fill(0);

JSON.parse(json, (k, v) => 
      v.amount ? info[Math.round((Date.now() - v.timestamp) / 8.64e7)] += v.amount : v)

console.log( JSON.stringify(info) );
0
Slai 19 nov. 2018 à 20:26

Peut-être un peu plus lisible avec les boucles for:

const data = [ { LQsZ2cuD1n5U10Rhg9p: { amount: 14, timestamp: 1541768493811 } }, 
               { LR6Bx6pih4TRID9i3LW: { amount: 24, timestamp: 1542014096044 } }, 
               { LR6IbF4Q0SI9TZ6Sh5h: { amount: 34, timestamp: 1542015841476 } }, 
               { LR6NLdgGd2UgTMpnYYE: { amount: 46, timestamp: 1542017084204 } }, 
               { LR6R5ql8lJW_gTctXB6: { amount: 11, timestamp: 1542018068191 } }, 
               { LR6R5v0ag8twyTjeupC: { amount: 12, timestamp: 1542018068351 } }, 
               { LR6R5xZZ4VNCIud71MP: { amount: 16, timestamp: 1542018069574 } }, 
               { LR6R5zz5QrvrM_RTrvT: { amount: 31, timestamp: 1542018069716 } }, 
               { LR6R6Aser7lmvrGetzm: { amount: 21, timestamp: 1542018069996 } }, ];

const info = Array(11).fill(0);

for (let obj of data)
  for (let key in obj)
    info[Math.round((Date.now() - obj[key].timestamp) / 864e5)] += obj[key].amount;

console.log( JSON.stringify(info) );

pour ... dans l'instruction pour énumérer les clés d'objet.

pour ... de la déclaration (nouveau dans ES6 et non pris en charge dans IE) pour itérer sur les valeurs des objets de type tableau.

Array(11) crée par lui-même un objet tableau vide (sans clés ni valeurs) de longueur 11, semblable à:

const info = [];
info.length = 11;

C'est pourquoi .fill(0) est utilisé pour le remplir avec 0 valeurs.

0
Slai 19 nov. 2018 à 19:43

Ok donc probablement la seule mauvaise chose à propos de la façon dont j'ai fait cela est que je profite du fait que tous les jours dans le tableau d'origine sont proches les uns des autres. Si vous deviez implémenter cela dans votre code, je recommanderais de prendre le temps de faire un meilleur travail pour trouver la différence dans le nombre de jours.

function reduce(array) {

        let resultArray = Array(11).fill(0);

        array.forEach(element => {
            var elementKey = Object.keys(element);
            var thisElement = element[elementKey];

            var date = new Date(thisElement.timestamp);
            var currentDate = new Date();

            var numOfDaysAgo = currentDate.getDate() - date.getDate();

            resultArray[numOfDaysAgo] += thisElement.amount;

        });

        return resultArray;

    }


    console.log(reduce(data));  //(11) [0, 0, 0, 0, 0, 0, 0, 195, 0, 0, 14]
0
Katie.Sun 19 nov. 2018 à 18:49

Vous pouvez obtenir un code un peu plus propre en supprimant les constructions enchaînées volumineuses et difficilement lisibles, ainsi qu'en supprimant ce nombre magique 8.64e7:

function process(data)
{
  // get rid of weird object keys
  let eventsArray = data.map(x => Object.values(x)[0]); // [{ amount, timestamp }, { amount, timestamp }, ...]
  
  // convert timestamp to date
  eventsArray.forEach(x => { // [{ amount, timestamp, date }, { amount, timestamp, date }...]
    x.date = new Date(x.timestamp).toLocaleDateString(); // consider using something better
  }); 
  
  // group and sum by date
  let byDate = eventsArray.reduce((dic, x) => {
    dic[x.date] = dic[x.date] === undefined ? x.amount : dic[x.date] + x.amount;
    return dic;
  }, {});
  
  return byDate;
}

const input = [{
    LQsZ2cuD1n5U10Rhg9p: {
      amount: 14,
      timestamp: 1541768493811
    }
  },
  {
    LR6Bx6pih4TRID9i3LW: {
      amount: 24,
      timestamp: 1542014096044
    }
  },
  {
    LR6IbF4Q0SI9TZ6Sh5h: {
      amount: 34,
      timestamp: 1542015841476
    }
  },
  {
    LR6NLdgGd2UgTMpnYYE: {
      amount: 46,
      timestamp: 1542017084204
    }
  },
  {
    LR6R5ql8lJW_gTctXB6: {
      amount: 11,
      timestamp: 1542018068191
    }
  },
  {
    LR6R5v0ag8twyTjeupC: {
      amount: 12,
      timestamp: 1542018068351
    }
  },
  {
    LR6R5xZZ4VNCIud71MP: {
      amount: 16,
      timestamp: 1542018069574
    }
  },
  {
    LR6R5zz5QrvrM_RTrvT: {
      amount: 31,
      timestamp: 1542018069716
    }
  },
  {
    LR6R6Aser7lmvrGetzm: {
      amount: 21,
      timestamp: 1542018069996
    }
  },
];

console.log(process(input));

Vous pouvez maintenant remplir les dates manquantes avec 0 si vous connaissez la plage de dates observées, ou simplement la transmettre à une bibliothèque de graphiques, elles peuvent généralement gérer les dates manquantes.

0
Yeldar Kurmangaliyev 19 nov. 2018 à 17:37