SitePoint Sponsor

User Tag List

Results 1 to 6 of 6
  1. #1
    SitePoint Zealot
    Join Date
    Dec 2006
    Location
    England, UK
    Posts
    160
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Problem Merging multi-dimensional arrays conditionally

    Hi

    Summary:
    I'm currently creating a script (for greasemonkey) that will eventually store a local copy of graph values, grabbed from a FusionCharts graph.

    I am currently getting stuck on how to structure the data, and then how to update it properly. At this point, what I need it to come up with the *how/what* to do, rather than the actual code (though that is the next step after this is sorted).

    Unfortunately, this is a bit of a headache-starter and I don't have anybody that I can ask/bounce ideas off in person, so I now throw down the gauntlet to all you SitePointers out there =P



    Here is the data structure that I have come up with so far, but it is becoming a PITA to come up with a function to update the values in storedData with those in newData...


    Data structure...
    Code:
    var storedData=
    [
      [referralID1,
        [ 
          [date1,actualClicks1,creditedClicks1,totalClicks1],
          [date2,actualClicks2,creditedClicks2,totalClicks2]
        ]
      ],
      [referralID2,
        [ 
          [date1,actualClicks1,creditedClicks1,totalClicks1],
          [date2,actualClicks2,creditedClicks2,totalClicks2]
        ]
      ],
      [referralID3,
        [ 
          [date1,actualClicks1,creditedClicks1,totalClicks1],
          [date2,actualClicks2,creditedClicks2,totalClicks2]
        ]
      ]
    ];
    
    
    var newData=
    [
      [referralID1,
        [ 
          [date2,actualClicks2,creditedClicks2,totalClicks2],
          [date3,actualClicks3,creditedClicks3,totalClicks3],
        ]
      ]
    ];

    I would be willing to consider JSON and other methods of creating some kind of relationship between the values, but for a quick and dirty attempt to get *something* working I've been trying to start with arrays.


    This morning I made an attempt at getting that something working (further down in the post if you are interested) and an afternoon away from the problem hasn't helped much. In the last hour I came up with this pseudo-function that should help outline the basics of what I am trying to do:

    Pseudo-function...
    Code:
    function updateStoredDataWith(newData)
    {
      // for each (referral in newData)
      {
        if(exists in storedData)
        {
          // Referral exists in both newData and storedData
          
          // for each (date in newData[i])
          {
            // if(newData[referral_i][date_j] exists in storedData[referral_i])
            {
              //[date1,actualClicks1,creditedClicks1,totalClicks1],
              // Overwrite storedData[referral_i][date_j][actualClicks] with newData[referral_i][date_j][actualClicks]
              // Overwrite storedData[referral_i][date_j][creditedClicks] with newData[referral_i][date_j][creditedClicks]
              // Overwrite storedData[referral_i][date_j][totalClicks] with newData[referral_i][date_j][totalClicks]
              
            }
            else
            {
              // Insert newData[referral_i][date_j] in storedData[referral_i]
            }
          }
        }
        else
        {
          // add all of newData[referral_i] to the end of storedData
        }
      }
    }






    This is the code that I have tried so far....
    You don't need to read further down but here is my attempt from this morning.
    I realised that I can't do it all in one go so I started by simplifying the inputs. I stopped at this point cos I was starting to think along the lines of "surely there must be an easier way...?"


    Code:
    /*
    var oldClicks = [referralID,
      [ 
        [date1,actualClicks1,creditedClicks1,totalClicks1],
        [date2,actualClicks2,creditedClicks2,totalClicks2]
      ]
    ];
    
    */
    
    
    var referralData_stored = new Array();
    referralData_stored =
    [
      ['R12345',
        [
          ['2009/11/30',0],
          ['2009/12/1',1],
          ['2009/12/2',2],
          ['2009/12/3',3]
        ]
      ]
    ];
    
    var referralData_new = new Array();
    referralData_new = 
    [
      ['R12345',
        [
          ['2009/12/3',3],
          ['2009/12/4',4],
          ['2009/12/5',5]
        ]
      ]
    ];
    
    
    function insertNewData(old,current)
    {
    console.info('current.length = '+current.length+'\n'+
    'old.length = '+old.length);
    console.info('current = '+current+'\n'+
    'old = '+old);
    
      for(var i = 0; i < current.length; i++)
      {
        console.info('i = '+i);
        var currentRef = current[i];
        var currentRefName = current[i][0];
        var currentRefDates = current[i][1];
        
        console.info('currentRef = '+currentRef+'\n'+
        'currentRefName = '+currentRefName+'\n'+
        'currentRefDates = '+currentRefDates);
        
        // Iterate through the referrals within the 'old' (stored) list
        for(var j = 0; j < old.length; j++)
        {
          console.info('j = '+j+'\n'+
          'old[j] = '+old[j]);
          
          var oldRef = old[j];
          var oldRefName = old[j][0];
          var oldRefDates = old[j][1];
          
          console.info('oldRef = '+oldRef+'\n'+
          'oldRefName = '+oldRefName+'\n'+
          'oldRefDates = '+oldRefDates);
          
          // Check if the current ref is already in the stored list
          if(currentRefName == oldRefName)
          {
            console.info('currentRefDates = '+currentRefDates+'\n'+
            'oldRefDates = '+oldRefDates);
            
            // Iterate through the dates for which data is already available for the current ref
            for(var k = 0; k < currentRefDates.length; k++)
            {
              console.info('k = '+k+'\n'+
              'currentRefDates[k] = '+currentRefDates[k]);
              
              // Check if the current ref has data for the currently selected date
              if(oldRefDates.indexOf(currentRefDates[k]) >= 0)
              {
                console.info('currentRefDates[k] is currently in the stored list. Overwrite it now.');
                
                // Insert the extra dates
                old[j][1].push(currentRefDates[k]);
              }
              else if(oldRefDates.indexOf(currentRefDates[k]) == -1)
              {
              console.info('currentRefDates[k] is not currently in the stored list. Adding it now.');
              
                // The data for this date does not currently exist
                old[j][1].push(currentRefDates[k]);
              }
            }
          }
          else
          {
            // The current ref does not currently have any stored data
            // push the data for the current ref to the stored data array
            
            // commented out
            // old.push(currentRef);
          }
        }
      }
      console.info('old[0].length = '+old[0].length+'\n'+
      'old = '+old);
      return old;
    }
    
    
    var mergedData = insertNewData(referralData_stored,referralData_new);
    
    console.info('mergedData.length = '+mergedData.length);
    console.info('mergedData[0] = '+mergedData[0]);
    console.info('mergedData[1] = '+mergedData[1]);
    console.info('mergedData[2] = '+mergedData[2]);
    console.info('mergedData[3] = '+mergedData[3]);


    Firebug Output:
    Code:
    Firebug's log limit has been reached. %S entries not shown.		Preferences	 
    >>> /* var oldClicks = [referralID, [ [date1,ac...onsole.info('mergedData[3] = '+mergedData[3]);
    
    current.length = 1
    old.length = 1
    
    current = R12345,2009/12/3,3,2009/12/4,4,2009/12/5,5
    old = R12345,2009/11/30,0,2009/12/1,1,2009/12/2,2,2009/12/3,3
    
    i = 0
    
    currentRef = R12345,2009/12/3,3,2009/12/4,4,2009/12/5,5 
    currentRefName = R12345 
    currentRefDates = 2009/12/3,3,2009/12/4,4,2009/12/5,5
    
    j = 0 
    old[j] = R12345,2009/11/30,0,2009/12/1,1,2009/12/2,2,2009/12/3,3
    
    oldRef = R12345,2009/11/30,0,2009/12/1,1,2009/12/2,2,2009/12/3,3 
    oldRefName = R12345 
    oldRefDates = 2009/11/30,0,2009/12/1,1,2009/12/2,2,2009/12/3,3
    
    currentRefDates = 2009/12/3,3,2009/12/4,4,2009/12/5,5 
    oldRefDates = 2009/11/30,0,2009/12/1,1,2009/12/2,2,2009/12/3,3
    
    k = 0 
    currentRefDates[k] = 2009/12/3,3
    
    currentRefDates[k] is not currently in the stored list. Adding it now.
    
    k = 1 currentRefDates[k] = 2009/12/4,4
    currentRefDates[k] is not currently in the stored list. Adding it now.
    
    k = 2 currentRefDates[k] = 2009/12/5,5
    currentRefDates[k] is not currently in the stored list. Adding it now.
    
    old[0].length = 2 
    old = R12345,2009/11/30,0,2009/12/1,1,2009/12/2,2,2009/12/3,3,2009/12/3,3,2009/12/4,4,2009/12/5,5
    
    mergedData.length = 1
    mergedData[0] = R12345,2009/11/30,0,2009/12/1,1,2009/12/2,2,2009/12/3,3,2009/12/3,3,2009/12/4,4,2009/12/5,5
    mergedData[1] = undefined
    mergedData[2] = undefined
    mergedData[3] = undefined

  2. #2
    SitePoint Zealot
    Join Date
    Dec 2006
    Location
    England, UK
    Posts
    160
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    My apologies for the length of the last post... I've been through many hours of head-scratching and I have many differing ideas floating about in my mind ...


    One thing that I hadn't considered before was XML because I hate its bloat, but for now at least it is the easiest way to describe the structure that I want...

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE refData [
      <!ELEMENT refData (referral*)>
        <!ELEMENT referral (clickData*,lastSeen)>
        <!ATTLIST referral refID CDATA #REQUIRED>
          <!ELEMENT lastSeen (#PCDATA)>
          <!ELEMENT clickData (actualClicks,creditedClicks,totalClicks)>
          <!ATTLIST clickData date CDATA #REQUIRED>
            <!ELEMENT actualClicks (#PCDATA)>
            <!ELEMENT creditedClicks (#PCDATA)>
            <!ELEMENT totalClicks (#PCDATA)>
    ]>
    
    <refData>
      <referral refID="R12345">
        <clickData date="09/12/2009">
          <actualClicks>0</actualClicks>
          <creditedClicks>0</creditedClicks>
          <totalClicks>8</totalClicks>
        </clickData>
        <clickData date="10/12/2009">
          <actualClicks>4</actualClicks>
          <creditedClicks>2</creditedClicks>
          <totalClicks>12</totalClicks>
        </clickData>
        <clickData date="11/12/2009">
          <actualClicks>4</actualClicks>
          <creditedClicks>4</creditedClicks>
          <totalClicks>16</totalClicks>
        </clickData>
        <lastSeen>Fri Dec 11 2009 15:36:58 GMT+0000 (BST)</lastSeen>
      </referral>
    </refData>

  3. #3
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2008
    Posts
    5,757
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    If you described the primary way you need to traverse and use this data, I think this would be an appropriate structure.
    Code:
    var data = {
        "R12345": {
            clickData: {
                "09/12/2009": {actualClicks: 0, creditedClicks: 0, totalClicks: 8},
                "10/12/2009": {actualClicks: 4, creditedClicks: 2, totalClicks: 12}
            },
            lastSeen: "Fri Dec 11 2009 15:36:58 GMT+0000 (BST)"
        },
        "R6789": {
            //same....
        }
    };
    Then you can easily look things up by using the refid and the date as the keys. Just loop through the new data
    Code:
    if (data[someRefId]) {
        // overwrite/create
        data[someRefId][someDate] = someNewData;
    }

  4. #4
    SitePoint Zealot
    Join Date
    Dec 2006
    Location
    England, UK
    Posts
    160
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by crmalibu View Post
    If you described the primary way you need to traverse and use this data, I think this would be an appropriate structure.
    I'm not sure how much of this will be relevant, but I have a set of referrals. In the 'wider' view, I have access to the refID (the ID of the referral) and the total # of clicks that they have done since the referral has been 'yours'. In this view, up to 300 referrals can be seen at one time.

    I can then 'zoom in' and view more details about individual referrals. This consists of the last 10 days, the number of clicks that the referral has made, and the number of those clicks that have been credited to 'me'.

    At any one point in time I will only have access to the last 10 days of data. For this reason I want to store a local copy of the data using greasemonkey so that my other scripts will have access to older data too.



    Quote Originally Posted by crmalibu View Post
    Code:
    var data = {
        "R12345": {
            clickData: {
                "09/12/2009": {actualClicks: 0, creditedClicks: 0, totalClicks: 8},
                "10/12/2009": {actualClicks: 4, creditedClicks: 2, totalClicks: 12}
            },
            lastSeen: "Fri Dec 11 2009 15:36:58 GMT+0000 (BST)"
        },
        "R6789": {
            //same....
        }
    };
    Then you can easily look things up by using the refid and the date as the keys. Just loop through the new data
    Code:
    if (data[someRefId]) {
        // overwrite/create
        data[someRefId][someDate] = someNewData;
    }



    I've had a quick play with this and aside from needing to use data[someRefId]['clickData'][someDate] being a slight pain (but I think I'm going to keep it there) , it is looking great =]


    As a small aside, I'm not 100% sure what to do about the dates/times - store them as dd/mm/yyyy or what. The script will be used worldwide and I realise that the dd/mm/yyyy may not always be appropriate (eg, the US uses mm/dd/yyyy ?)

    The 'lastSeen' field may be shared between people and having an indication of timezone offsets etc is probably needed. Would the output of new Date() be sufficient or can you suggest something else?

  5. #5
    SitePoint Zealot
    Join Date
    Dec 2006
    Location
    England, UK
    Posts
    160
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I'm almost embarrassed that this has taken so long to sort out and how convoluted my other attempts have been, but here's my working code thus far. As you can see from the code, it updates the old JSON structure from another JSON structure, but my next step is to change it so that it uses the commented out function declaration instead.

    Thanks for the nudge in the right direction =]

    Code:
    var data = {
        "R12345": {
            clickData: {
                "09/12/2009": {actualClicks: 0, creditedClicks: 0, totalClicks: 8},
                "10/12/2009": {actualClicks: 4, creditedClicks: 2, totalClicks: 12},
            },
            lastSeen: "Thu Dec 10 2009 15:36:58 GMT+0000 (BST)"
        }
    };
    
    var newData = {
        "R12345": {
            clickData: {
                "10/12/2009": {actualClicks: 4, creditedClicks: 4, totalClicks: 12},
                "11/12/2009": {actualClicks: 4, creditedClicks: 4, totalClicks: 16},
            },
            lastSeen: "Fri Dec 11 2009 02:36:58 GMT+0000 (BST)"
        },
        "R123456": {
            clickData: {
                "11/12/2009": {actualClicks: 0, creditedClicks: 0, totalClicks: 8},
            },
            lastSeen: "Fri Dec 11 2009 02:36:58 GMT+0000 (BST)"
        }
    };
    
    
    //function updateStoredData(refID,actualClicks,creditedClicks,totalClicks)
    function updateStoredData(data,newData)
    {
      for(var newRefID in newData) 
      {
        console.group();
        // if 'new' ref exists in storage
        if(data[newRefID]) 
        {
          for(var newDate in newData[newRefID]['clickData']) 
          {
            console.group();
            // if data for the current ref and current date exists in storage
            if(data[newRefID]['clickData'][newDate]) 
            {
              if(newData[newRefID]['clickData'][newDate]['totalClicks'] >= 0) 
              {
                data[newRefID]['clickData'][newDate]['totalClicks'] = newData[newRefID]['clickData'][newDate]['totalClicks']; 
              }
              if(newData[newRefID]['clickData'][newDate]['actualClicks'] >= 0 && newData[newRefID]['clickData'][newDate]['creditedClicks'] >= 0) 
              {
                data[newRefID]['clickData'][newDate]['actualClicks'] = newData[newRefID]['clickData'][newDate]['actualClicks']; 
                data[newRefID]['clickData'][newDate]['creditedClicks'] = newData[newRefID]['clickData'][newDate]['creditedClicks']; 
              }
            }
            else
            {
              data[newRefID]['clickData'][newDate] = newData[newRefID]['clickData'][newDate];
            }
            data[newRefID]['lastSeen'] = new Date();
            console.groupEnd();
          }
        }
        else
        {
          data[newRefID] = newData[newRefID];
          data[newRefID]['lastSeen'] = new Date();
        }
        console.groupEnd();
      }
    }
    
    updateStoredData(data,newData);
    
    //console.info(newData['R12345']['clickData']['09/12/2009']);
    console.info(data);

  6. #6
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2008
    Posts
    5,757
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    For storing the date/time, I would probably lean towards either a unix timestamp, or one of the formats that falls within https://developer.mozilla.org/en/Cor...cts/Date/parse

    Then use something like toLocaleString() to display


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •