17 Replies Latest reply on Sep 25, 2009 12:54 PM by David_F57

    Processing duplicates in a collection?

    Handycam Level 1

      I need to go through an XMLListCollection (or XMLList), look for items with matching attributes, combine the duplicates, and then output the resulting lit into a new XMLListCollection.

       

      For example, if my collection contains
      <item qty="3.25" units="lbs." desc="sweet potatoes" />
      <item qty="2.5" units="lbs." desc="sweet potatoes" />
      <item qty="1" units="lbs." desc="sweet potatoes" />

       

      I need to end up with
      <item qty="6.75" units="lbs." desc="sweet potatoes" />

       

      So I need to look through he collection, identify all the items where "desc" attribute is the same, add up their "qty" attributes, and then add this as one item to a new collection with the total in its "qty".

       

      Any suggestions?

        • 1. Re: Processing duplicates in a collection?
          David_F57 Level 5

          really all you could do is iterate through the list

           

          if item description in list  1 is found in list 2 item in list 2 value is accumulated else item 1 is added to list 2

           

          var found:boolean=false;

          for (var i:number=0; li < list1.length;i++)

          {

             found=false;  

             while (found==false && j < list2.length)

            {

               for (var j:number=0; j < list2.length;j++)

              {

                (if list2[j].description == list1[i].description)

                {

                    found=true;

                    list2[j].value += list1[i].value;

                    j=list2.length; 

                }

               if (found==false) { just append the list1[i] info to list2} 

              }

            }

          }

           

          David.   

          • 2. Re: Processing duplicates in a collection?
            Handycam Level 1

            I'm having some problems with the concept in the nested loops in your example.  I corrected a couple of typos in your code and plugged it is as such:

             

            private function checkDupes(list1:XML):void {
                 var found:Boolean=false;
                 var len:int = list1.item.length();
                 var list2:XML = new XML();
                 
                 for (var i:int=0; i < len;i++)
                 {
                      trace("checking item "+i+" which is "+list1.item[i].@desc);
                      while (found==false && j < list2.length)
                      {
                           found=false;   
                           for (var j:Number=0; j < list2.length;j++)
                           {
                                trace("checking");
                                if (list2[j].item[i].@desc == list1[i].item[i].@desc)
                                {
                                     found=true;
                                     list2[j].value += list1[i].value;
                                     j=list2.length;  
                                } 
                                if (found==false) { 
                                     //just append the list1[i] info to list2
                                     list2.appendChild(list1.item[i]);
                                }  
                           }
                      } 
                 }
                 trace("list2="+list2);
            }
            

             

            However, you don't define "j" until after you try and use it in that while loop.  So at the point the while loop starts j=NaN, and the loop never happens (that trace of "checking" never traces.  So the whole thing is dead in the water.

             

            I can try and modify the loop to fix this, but I am confused how that whole part would work...

            • 3. Re: Processing duplicates in a collection?
              David_F57 Level 5

              Sorry, I just typed my thoughts straight into the reply, so no testing

               

              Anyway here is a bit of code that does work, it can be cleaner but I was limited for time plus i was being driven crazy by a bug in fb beta 2 which cost me about 2 hours of chasing a coding problem that wasn't a coding problem.

               

              <?xml version="1.0" encoding="utf-8"?>

              <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"

                                                  xmlns:s="library://ns.adobe.com/flex/spark"

                                                  xmlns:mx="library://ns.adobe.com/flex/halo" minWidth="1024" minHeight="768" creationComplete="initApp()">

               

                   <fx:Script>

                        <![CDATA[

                             import mx.collections.ArrayCollection;

                             

                             [Bindable] private var arr1:ArrayCollection = new ArrayCollection();

                             [Bindable] private var arr2:ArrayCollection = new ArrayCollection();

                             

                             private function initApp(): void

                             {

                                  arr1.addItem({id:1,desc:"Apple",qty:12});

                                  arr1.addItem({id:2,desc:"Orange",qty:5});

                                  arr1.addItem({id:3,desc:"Banana",qty:3});

                                  arr1.addItem({id:1,desc:"Apple",qty:12});

                                  arr1.addItem({id:2,desc:"Orange",qty:5});

                                  arr1.addItem({id:3,desc:"Banana",qty:3});

                                  arr1.addItem({id:1,desc:"Apple",qty:12});

                                  arr1.addItem({id:2,desc:"Orange",qty:5});

                                  arr1.addItem({id:3,desc:"Banana",qty:3});

                                  arr1.addItem({id:1,desc:"Apple",qty:12});

                                  arr1.addItem({id:2,desc:"Orange",qty:5});

                                  arr1.addItem({id:3,desc:"Banana",qty:3});                    

                             }

                             

                             private function getUnique(e:Event): void

                             {

                                  var found:Boolean=false;

                                  var j:int=0;

                                  var k:int=0;

                                  arr2.removeAll();

                                  arr2.addItem(arr1[0]);

                                  for (var i:int=1;i < arr1.length;i++)

                                  {

                                       found=false;

                                       k=arr2.length;

                                       j=0;

                                       for (j=0;j < k;j++)

                                       {

                                            if (arr2[j].desc == arr1[i].desc)

                                            {

                                                 arr2[j].qty += arr1[i].qty;

                                                 found = true;

                                            }     

                                       }

                                       if (!found) arr2.addItem(arr1[i]);

                                  }

                             }     

                        ]]>

                   </fx:Script>

                   

                   <mx:DataGrid x="28" y="35" height="465" dataProvider="{arr1}">

                        <mx:columns>

                             <mx:DataGridColumn headerText="item" dataField="id"/>

                             <mx:DataGridColumn headerText="description" dataField="desc"/>

                             <mx:DataGridColumn headerText="quantity" dataField="qty"/>

                        </mx:columns>

                   </mx:DataGrid>

                   <mx:DataGrid x="431" y="35" width="303" height="465" dataProvider="{arr2}">

                        <mx:columns>

                             <mx:DataGridColumn headerText="description" dataField="desc"/>

                             <mx:DataGridColumn headerText="quantity" dataField="qty"/>

                        </mx:columns>

                   </mx:DataGrid>

                   <s:Button x="338" y="35" label="Unique &gt;&gt;" click="getUnique(event)"/>

              </s:Application>

              • 4. Re: Processing duplicates in a collection?
                Handycam Level 1

                Thanks.  Only problem I have is my quantities are being treated as strings instead of numbers...

                 

                 

                private function getUnique(): void
                               {
                                    var len1:int = sl1.length;
                                    var found:Boolean=false;
                                    var j:int=0;
                                    var k:int=0;
                                    sl2.removeAll();
                                    sl2.addItem(sl1[0]);
                                    for (var i:int=1;i < len1;i++)
                                    {
                                         found=false;
                                         k=sl2.length;
                                         j=0;
                                         for (j=0;j < k;j++)
                                         {
                                              if (sl2[j].@sdesc == sl1[i].@sdesc)
                                              {
                                                   sl2[j].@qty += sl1[i].@qty;
                                                   found = true;
                                              }     
                                         }
                                         if (!found) sl2.addItem(sl1[i]);
                                    }
                               }
                

                 

                So the qty column in sl2 read "4 2" where it should be "6".  I tried Number(sl2[j].@qty) but that didn't work.

                • 5. Re: Processing duplicates in a collection?
                  Peter deHaan Level 4

                  Instead of Number(X) try parseFloat(X).

                   

                  Peter

                  • 6. Re: Processing duplicates in a collection?
                    Handycam Level 1

                    This is outstanding, and almost there... but every time the function is called, it keeps adding the items.

                     

                    How could this be modified so the result list's qty values are cleared every time?

                     

                    In your code, clicking the button gives you 48 apples, which is correct. But clicking the button again give you 96, not what I need.  I need to re-process the list, looking for any other apples that may have been added to it from another process, and get a total -- not add the apples it already added.  If there are 48 apples on the left, it needs to always be 48 on the right.

                     

                    I would have thought the line arr2.removeAll();  would have done the trick, but it apparently doesn't.  Any suggestions?

                    • 7. Re: Processing duplicates in a collection?
                      David_F57 Level 5

                      Hi,

                       

                      I am getting this issue with latest eng drop I'll see if I can work out what the issue is, maybe need to revert back to the supplied sdk. Give me 1/2 an hour

                       

                      David

                      • 8. Re: Processing duplicates in a collection?
                        David_F57 Level 5

                        Now I am completely confused, i've tried everything form removeing items one at a time to recreating an array each time I repopulate the second grid, tried with latest sdk, provided fb beta 2 sdk,  3.4 sdk, and different copying across the grids seems that the thing just continues to assume it has data, its like the bug in textfield where the content wasn't being released properly. I'll put a test case up on jira and see if the adobe guys have an answer.

                        • 9. Re: Processing duplicates in a collection?
                          Handycam Level 1

                          Thanks.  I am a beta tester as well.  At least now I know it wasn't just me

                           

                          • 10. Re: Processing duplicates in a collection?
                            David_F57 Level 5

                            I've logged a bug in jira- hopefully someone may know whats going on.

                             

                            https://bugs.adobe.com/jira/browse/FB-23091

                            • 11. Re: Processing duplicates in a collection?
                              David_F57 Level 5

                              Ok feed back from jira suggests an issue with arr1 also updating, this is a worry but for the moment tmy solution is to change from adding arr1 item to arr2 by explicitly declaring a new object.

                               

                              change to the if not found routine.

                              if (!found)

                              {

                              var newData:Object = {

                              desc:  arr1[i].desc,

                              qty :  arr1[i].qty

                              }

                              arr2.addItem(newData);

                              }

                               

                               

                               

                               

                              full code (this is slightly different in behaviour to the original example due to an error I found in the looping.)

                              <?xml version="1.0" encoding="utf-8"?>

                              <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"

                                 xmlns:s="library://ns.adobe.com/flex/spark"

                                 xmlns:mx="library://ns.adobe.com/flex/halo" minWidth="1024" minHeight="768" creationComplete="initApp()">

                              <fx:Script>

                              <![CDATA[

                              import mx.collections.ArrayCollection;

                               

                              [Bindable] private var arr1:ArrayCollection = new ArrayCollection();

                              [Bindable] private var arr2:ArrayCollection = new ArrayCollection();

                               

                              private function initApp(): void

                              {

                              arr1.addItem({id:1,desc:"Apple",qty:12});

                              arr1.addItem({id:2,desc:"Orange",qty:5});

                              arr1.addItem({id:3,desc:"Banana",qty:3});

                              arr1.addItem({id:4,desc:"Apple",qty:12});

                              arr1.addItem({id:5,desc:"Orange",qty:5});

                              arr1.addItem({id:6,desc:"Banana",qty:3});

                              arr1.addItem({id:7,desc:"Apple",qty:12});

                              arr1.addItem({id:8,desc:"Orange",qty:5});

                              arr1.addItem({id:9,desc:"Banana",qty:3});

                              }

                               

                              private function updateList(): void

                              {

                              var found:Boolean=false;

                              var i:int=0;

                              var j:int=0;

                              var k:int=0;

                              for (i=0;i < arr1.length;i++)

                              {

                              found=false;

                              k=arr2.length;

                              j=0;

                              for (j=0;j < k;j++)

                              {

                              if (arr2[j].desc == arr1[i].desc)

                              {

                              arr2[j].qty += arr1[i].qty;

                              found = true;

                              }

                              }

                              if (!found)

                              {

                              var newData:Object = {

                              desc:  arr1[i].desc,

                              qty :  arr1[i].qty

                              }

                              arr2.addItem(newData);

                              }

                              }

                              }

                               

                              private function getUnique(e:Event): void

                              {

                              arr2.removeAll();

                              updateList();

                              }

                               

                              private function clearData(e:Event): void

                              {

                              while (arr2.length > 0) arr2.list.removeItemAt(0);

                              }

                              ]]>

                              </fx:Script>

                               

                              <mx:DataGrid x="28" y="35" height="465" dataProvider="{arr1}">

                              <mx:columns>

                              <mx:DataGridColumn headerText="item" dataField="id"/>

                              <mx:DataGridColumn headerText="description" dataField="desc"/>

                              <mx:DataGridColumn headerText="quantity" dataField="qty"/>

                              </mx:columns>

                              </mx:DataGrid>

                              <mx:DataGrid id="dg1" x="431" y="35" width="303" height="465" dataProvider="{arr2}">

                              <mx:columns>

                              <mx:DataGridColumn headerText="description" dataField="desc"/>

                              <mx:DataGridColumn headerText="quantity" dataField="qty"/>

                              </mx:columns>

                              </mx:DataGrid>

                              <s:Button x="338" y="35" label="Refresh" width="85" click="getUnique(event)" />

                              <s:Button x="338" y="85" label="Clear" width="85" click="clearData(event)" />

                              </s:Application>

                               

                               

                              see if this does the job

                              David.

                              1 person found this helpful
                              • 12. Re: Processing duplicates in a collection?
                                David_F57 Level 5

                                Ok, coffee and a smoke to clear the head...

                                 

                                So arr2 by default became a pointer (maybe unique but a pointer) to arr1. I should have seen this. So maybe we need to have explicit routines for arraycollection addItem-pointer, addNewItem explicit duplication of object. Any thoughts ?

                                 

                                David

                                • 13. Re: Processing duplicates in a collection?
                                  Handycam Level 1

                                  That's pretty cool.  It indeed works in the simple proof-of-concept app.  However, in my app, in the end where you create a new object with 2 properties I need to actually pass the whole XML node along into the second list.

                                   

                                  For example, instead of the simple:

                                  arr1.addItem({id:1,desc:"Apple",qty:12});
                                  arr1.addItem({id:2,desc:"Orange",qty:5});
                                  arr1.addItem({id:3,desc:"Banana",qty:3});
                                  

                                  I have an XMLList containing:

                                  <item qty="1" units="lb." caption="crusty Italian or French bread" desc="bread" section="other" />
                                  <item qty="2" units="oz." caption="unsalted butter" desc="unsalted butter" section="dairy" />
                                  <item qty="2" units="lb." caption="medium-large yellow onions" desc="yellow onion" section="produce" />
                                  <item qty="4" units="oz." caption="unsalted butter" desc="unsalted butter" section="dairy" />
                                  

                                  The principle is the same, and as I tried tracing various parts of the function, it is making the comparison fine.  My problem is where you have

                                  if (!found) {
                                   var newData:Object = {desc:  arr1[i].desc, qty :  arr1[i].qty}
                                   arr2.addItem(newData);
                                   }
                                  

                                  instead of the simple object in the test case, I need to create an xml node "item" with attributes qty,units,caption,desc,section.

                                   

                                  So I changed the function like so, and now the matching items' quantities don't add for some reason:

                                  private function updateList(): void
                                  {
                                       var found:Boolean=false;
                                       var i:int=0;
                                       var j:int=0;
                                       var k:int=0;
                                       for (i=0;i < shoppingListCollection1.length;i++)
                                       {
                                            found=false;
                                            k=shoppingListCollection2.length;
                                            j=0;
                                            for (j=0;j < k;j++)
                                            {
                                                 if (shoppingListCollection2[j].desc == shoppingListCollection1[i].@desc)
                                                 {
                                                      shoppingListCollection2[j].@qty += shoppingListCollection1[i].@qty;
                                                      found = true;
                                                 }
                                            }
                                            if (!found)
                                            {
                                                 var newXML:XML  = <item/>;
                                                 newXML.@qty = shoppingListCollection1[i].@qty;
                                                 newXML.@units = shoppingListCollection1[i].@units;
                                                 newXML.@caption = shoppingListCollection1[i].@caption;
                                                 newXML.@desc = shoppingListCollection1[i].@desc;
                                                 newXML.@section = shoppingListCollection1[i].@section;
                                                 
                                                 shoppingListCollection2.addItem(newXML);
                                            }
                                       }
                                       
                                       groupingColl = new GroupingCollection2();
                                       groupingColl.source = shoppingListCollection2.source;
                                       var groupingInst:Grouping = new Grouping();
                                       groupingInst.fields = [new GroupingField("@section")];
                                       groupingColl.grouping = groupingInst;
                                       groupingColl.refresh(false);  
                                  }
                                  
                                  private function getUnique(): void
                                  {
                                       shoppingListCollection2.removeAll();
                                       updateList();
                                  }
                                  
                                  private function clearData(e:Event): void
                                  {
                                       while (shoppingListCollection2.length > 0) shoppingListCollection2.list.removeItemAt(0);
                                  }
                                  

                                  What did I miss?

                                  • 14. Re: Processing duplicates in a collection?
                                    David_F57 Level 5

                                              for (j=0;j < k;j++)
                                              {
                                                   if (shoppingListCollection2[j].desc == shoppingListCollection1[i].@desc)
                                                   {
                                                        shoppingListCollection2[j].@qty += shoppingListCollection1[i].@qty;
                                                        found = true;
                                                   }
                                              }
                                    
                                    observe the shoppingLstCollection2[j].desc    - is there possibly a @ missing...

                                    • 15. Re: Processing duplicates in a collection?
                                      Handycam Level 1

                                      Of course!  I am getting bleary-eyed from all this code.

                                       

                                      Only problem I am have now is that when it adds the @qty together in is concatenating them as strings instead of numbers:

                                       

                                      http://grab.by/64A

                                       

                                      So I did this:

                                       

                                      shoppingListCollection2[j].@qty = String(Number(shoppingListCollection2[j].@qty)+Number(shoppingListCollection1[i].@qty));

                                      and voila!  Many, many thanks.  I owe you a beer.

                                      • 16. Re: Processing duplicates in a collection?
                                        David_F57 Level 5

                                        Don't try to over complicate things you have strings- the following shows how simple it is to add 2 strings together then send the result back to a string.

                                         

                                        var S1:String = "12.5";

                                        var S2:String = "11.2";

                                        var N1:Number = Number(S1)+Number(S2);

                                        txt.text = String(N1);

                                         

                                        David.

                                        • 17. Re: Processing duplicates in a collection?
                                          David_F57 Level 5

                                          I think we both have bleary eyes I didn't see the last line of your post, for me its becuase the sun is about to come up.

                                           

                                          David.