Mega Code Archive

 
Categories / C# / Collections Data Structure
 

Counting the distribution of the values in an array

// // (C) Copyright 2009 Irantha Suwandarathna (irantha@gmail.com) // All rights reserved. // /* Copyright (c) 2001-2008, The HSQL Development Group * All rights reserved. * * Redistribution and use _in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions _in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer _in the documentation * and/or other materials provided with the distribution. * * Neither the name of the HSQL Development Group nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG, * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace EffiProz.Core.Lib {     /**    * Collection of routines for counting the distribution of the values    * _in an int[] array.    *    * @author fredt@users    * @version 1.7.2    * @since 1.7.2    */     public class ArrayCounter     {         /**          * Returns an int[] array of length segments containing the distribution          * count of the elements _in unsorted int[] array with values between min          * and max (range). Values outside the min-max range are ignored<p>          *          * A usage example is determining the count of people of each age group          * _in a large int[] array containing the age of each person. Called with          * (array, 16,0,79), it will return an int[16] with the first element          * the count of people aged 0-4, the second element the count of those          * aged 5-9, and so on. People above the age of 79 are excluded. If the          * range is not a multiple of segments, the last segment will be cover a          * smaller sub-range than the rest.          *          */         public static int[] countSegments(int[] array, int elements,                                           int segments, int start, int limit)         {             int[] counts = new int[segments];             long interval = calcInterval(segments, start, limit);             int index = 0;             int element = 0;             if (interval <= 0)             {                 return counts;             }             for (int i = 0; i < elements; i++)             {                 element = array[i];                 if (element < start || element >= limit)                 {                     continue;                 }                 index = (int)((element - start) / interval);                 counts[index]++;             }             return counts;         }         /**          * With an unsorted int[] array and with target a positive integer _in the          * range (1,array.Length), finds the value _in the range (start,limit) of the          * largest element (rank) where the count of all smaller elements _in that          * range is less than or equals target. Parameter margin indicates the          * margin of error _in target<p>          *          * In statistics, this can be used to calculate a median or quadrile value.          * A usage example applied to an array of age values is to determine          * the maximum age of a given number of people. With the example array          * given _in countSegments, rank(array, c, 6000, 18, 65, 0) will return an age          * value between 18-64 (inclusive) and the count of all people aged between          * 18 and the returned value(exclusive) will be less than or equal 6000.          *          */         public static int rank(int[] array, int elements, int target, int start,                                int limit, int margin)         {             const int segments = 256;             int elementCount = 0;             int currentLimit = limit;             for (; ; )             {                 long interval = calcInterval(segments, start, currentLimit);                 int[] counts = countSegments(array, elements, segments, start,                                              currentLimit);                 for (int i = 0; i < counts.Length; i++)                 {                     if (elementCount + counts[i] < target)                     {                         elementCount += counts[i];                         start += (int)interval;                     }                     else                     {                         break;                     }                 }                 if (elementCount + margin >= target)                 {                     return start;                 }                 if (interval <= 1)                 {                     return start;                 }                 currentLimit = start + interval < limit ? (int)(start + interval)                                                         : limit;             }         }         /**          * Helper method to calculate the span of the sub-interval. Simply returns          * the cieling of ((limit - start) / segments) and accounts for invalid          * start and limit combinations.          */         static long calcInterval(int segments, int start, int limit)         {             long range = limit - start;             if (range < 0)             {                 return 0;             }             int partSegment = (range % segments) == 0 ? 0                                                       : 1;             return (range / segments) + partSegment;         }     } }