Solved: How to create a new list from two partial lists & based on one partial list?

Question

Asked by RobbB on November 02, 2021 (source).

This requires some genius, experience & knowledge I don't yet have in Dart, so I'm looking for help.

I am trying to populate a line chart, when users first begin using software there will be "empty" entries in the chart data. There also may be "zero" entries or no entry at all for some weeks or entries. I want to ensure that my line chart shows zero (for sales income - yAxis) for any missing entries based on a graph with 13 entries shown always.

For example mockupGraphData would be an existing situation where a couple sales dates are missing entries (based on weekly entries) and there are not enough entries to satisfy the graph appetite.

I would like to automatically enter "zeroed" dates. Where the date would be the index of missing date and GraphData.yAxis (income) would be zero.

Below does not compile of course, consider the last loop pseudo code of what I think would work if I could get around the index not existing in the mockupGraphData...

void main() {
  
  // Actual "mock" input data
  List<GraphData> mockupGraphData = [
    GraphData(1586761200000, 145333),
    GraphData(1587366000000, 433343),
    GraphData(1587970800000, 223432),
    GraphData(1589180400000, 122221),
    GraphData(1589785200000, 982347),
    GraphData(1590994800000, 234322),
  ];
  
  // Required graph dates as per below calculations (13 entries):
    // 1583737200000
    // 1584342000000
    // 1584946800000
    // 1585551600000
    // 1586156400000
    // 1586761200000
    // 1587366000000
    // 1587970800000
    // 1588575600000
    // 1589180400000
    // 1589785200000
    // 1590390000000
    // 1590994800000

  int entries = 13;
  int latestDateReported = DateTime(2020, 6, 1).millisecondsSinceEpoch;
  int oneWeek = Duration(days: 7).inMilliseconds;
  int earliestEntryDate = latestDateReported - (oneWeek * entries);
  List<int> graphRequiredDates = [];
  List<GraphData> finalData = [];
  
  for (int i = 0; i < entries; i++) {
    earliestEntryDate += oneWeek;
    graphRequiredDates.add(earliestEntryDate);
  }
  // What I would like to do
  for (int i = 0; i < entries; i++) {
    if (!mockupGraphData.contains(GraphData(graphRequiredDates[i]))) {
      finalData.add(GraphData(graphRequiredDates[i], 0));
    }
  }
  
  print(finalData);
}

class GraphData {
    int xAxis; // Sale date
    int yAxis; // Sale income
  
  GraphData(this.xAxis, this.yAxis);
  
  @override
  String toString() {
    return '$xAxis $yAxis';
  }
  }
// IDEAL OUTPUT:
  List<GraphData> mockupGraphData = [
    GraphData(1583737200000, 0),
    GraphData(1584342000000, 0),
    GraphData(1584946800000, 0),
    GraphData(1585551600000, 0),
    GraphData(1586156400000, 0),
    GraphData(1586761200000, 145333),
    GraphData(1587366000000, 433343),
    GraphData(1587970800000, 223432),
    GraphData(1588575600000, 0),
    GraphData(1589180400000, 122221),
    GraphData(1589785200000, 982347),
    GraphData(1590390000000, 0),
    GraphData(1590994800000, 234322),
  ];

Answer

Question answered by jamesdlin (source).

Instead of storing mockupGraphData as a List<GraphData>, I would use a Map<int, int> that maps timestamps to values. From there, it's easy to iterate over your list of expected timestamps, check if a timestamp already exists in mockupGraphData, and then construct GraphData objects appropriately.

You additionally can use collection-for to make some of your code neater:

void main() {
  // Actual "mock" input data

  var mockupGraphData = <int, int>{
    1586761200000: 145333,
    1587366000000: 433343,
    1587970800000: 223432,
    1589180400000: 122221,
    1589785200000: 982347,
    1590994800000: 234322,
  };

  int entries = 13;
  int latestDateReported = DateTime(2020, 6, 1).millisecondsSinceEpoch;
  int oneWeek = Duration(days: 7).inMilliseconds;
  int earliestEntryDate = latestDateReported - (oneWeek * (entries - 1));
  List<int> graphRequiredDates = [
    for (var i = 0; i < entries; i++)
      earliestEntryDate + i * oneWeek,
  ];
  List<GraphData> finalData = [
    for (var requiredDate in graphRequiredDates)
      GraphData(requiredDate, mockupGraphData[requiredDate] ?? 0),
  ];

  finalData.forEach(print);
}

class GraphData {
  int xAxis; // Sale date
  int yAxis; // Sale income

  GraphData(this.xAxis, this.yAxis);

  @override
  String toString() {
    return 'GraphData($xAxis, $yAxis)';
  }
}
ARRAYLIST DART FLUTTER LOOPS
SHARE: