public static List <Tuple <double, double> > Calculate(List <double?> data, List <double?> weights, int classes)
        {
            double totalPopulation;
            List <KeyValuePair <double, double> > dataWeighted = CreateSortedList(data, weights, out totalPopulation);

            if (dataWeighted.Count <= classes)
            {
                return(JenksNaturalBreaks.CreateMiminalList(GetKeys(dataWeighted), classes));
            }

            // Ahora itera por la lista ordenada armando las clases
            List <Tuple <double, double> > ret = new List <Tuple <double, double> >();
            double cutInterval           = totalPopulation / classes;
            double nextCutPoint          = cutInterval;
            double lastEffectiveCutPoint = dataWeighted[0].Key;
            double cummulatedSum         = 0;
            double lastItemValue         = lastEffectiveCutPoint;

            foreach (var item in dataWeighted)
            {
                if (lastItemValue != item.Key &&
                    cummulatedSum >= nextCutPoint)
                {
                    ret.Add(new Tuple <double, double>(lastEffectiveCutPoint, item.Key));
                    lastEffectiveCutPoint = item.Key;
                    nextCutPoint         += cutInterval;
                }
                lastItemValue = item.Key;
                // Arrastra la suma acumulada
                cummulatedSum += item.Value;
            }
            ret.Add(new Tuple <double, double>(lastEffectiveCutPoint, lastItemValue));

            return(ret);
        }
        public void testEvaluateWithExpressions()
        {
            double[] data  = new double[] { 4, 90, 20, 43, 29, 61, 8, 12 };
            var      jenks = JenksNaturalBreaks.Calculate(data, 2);

            // the values being quantiled are
            // {4,90,20,43,29,61,8,12};
            // so there should be two groups:
            // {4, 8, 12, 20} 4 <= x < 29
            // {29, 43, 61, 90} 29 <= x <= 90
            assertEquals(2, jenks.Count);
            assertEquals("4..29", ToPair(jenks[0]));
            assertEquals("29..90", ToPair(jenks[1]));
        }
        // Rework to test with Jenks71 data
        // Answer (from R) is [15.57,41.2] (41.2,60.66] (60.66,77.29] (77.29,100.1] (100.1,155.3]
        public void testEvaluateRealData()
        {
            double[] jenks71 = new double[] { 50.12, 83.9, 76.43, 71.61, 79.66, 84.84, 87.87, 92.45, 119.9,
                                              155.3, 131.5, 111.8, 96.78, 86.75, 62.41, 96.37, 75.51, 77.29, 85.41, 116.4, 58.5, 75.29,
                                              66.32, 62.65, 80.45, 72.76, 63.67, 60.27, 68.45, 100.1, 55.3, 54.07, 57.49, 73.52,
                                              68.25, 64.28, 50.64, 52.47, 68.19, 57.4, 39.72, 60.66, 57.59, 38.22, 57.22, 67.04,
                                              47.29, 71.05, 50.53, 34.63, 59.65, 62.06, 52.89, 56.35, 57.26, 53.77, 59.89, 55.44,
                                              45.4, 52.21, 49.38, 51.15, 54.27, 54.32, 41.2, 34.58, 50.11, 52.05, 33.82, 39.88,
                                              36.24, 41.02, 46.13, 51.15, 32.28, 33.26, 31.78, 31.28, 50.52, 47.21, 32.69, 38.3,
                                              33.83, 40.3, 40.62, 32.14, 31.66, 26.09, 39.84, 24.83, 28.2, 31.19, 37.57, 27.16,
                                              23.42, 18.57, 30.97, 17.82, 15.57, 15.93, 28.71, 32.22 };

            var jenks = JenksNaturalBreaks.Calculate(jenks71, 5);

            assertEquals(5, jenks.Count);

            assertEquals("15.57..41.2", ToPair(jenks[0]));
            assertEquals("41.2..60.66", ToPair(jenks[1]));
            assertEquals("60.66..77.29", ToPair(jenks[2]));
            assertEquals("77.29..100.1", ToPair(jenks[3]));
            assertEquals("100.1..155.3", ToPair(jenks[4]));
        }
        /// <summary>
        /// Test a feature collection where each feature will be in it's own bin.
        ///
        /// Creates a feature collection with five features 1-5. Then uses the quantile function to put
        /// these features in 5 bins. Each bin should have a single feature.
        /// </summary>
        public void testSingleBin()
        {
            // create a feature collection with five features values 1-5
            var data = new double[] { 1, 2, 3, 4, 5 };
            // run the quantile function
            var jenks = JenksNaturalBreaks.Calculate(data, 5);

            assertEquals(5, jenks.Count);
            for (int i = 0; i < 5; i++)
            {
                assertEquals(i + 1, jenks[i].Item1);
                if (i != 4)
                {
                    assertEquals("wrong value for max", i + 2, (int)jenks[i].Item2);
                    assertEquals("bad title", (i + 1) + ".." + (i + 2), ToPair(jenks[i]));
                }
                else
                {
                    assertEquals("wrong value for max", i + 1, (int)jenks[i].Item2);
                    assertEquals("bad title", (i + 1) + ".." + (i + 1), ToPair(jenks[i]));
                }
            }
        }