Remove duplicates from INT/FLOAT array

Become a member of the CGSociety

Connect, Share, and Learn with our Large Growing CG Art Community. It's Free!

THREAD CLOSED
 
Thread Tools Search this Thread Display Modes
  01 January 2011
Remove duplicates from INT/FLOAT array

hi,
im looking for something like stringArrayRemoveDuplicates() that works with int / float array. pls help
 
  01 January 2011
this is not really a hard funtion to write yourself, but you may have already noticed that stringArrayRemoveDuplicates is actually a MEL script, not a command. As this is the case you can just open it up and copy it. then just modify it slightly to work on ints or floats depending on your needs (it must be one or the other as MEL must return a specific type.)

:nathaN
 
  01 January 2011
Post Something like this?

global proc int[] intArrayRemoveDuplicates( int $intArr[] )
  {
  	int $resuts[];
  
  	for( $intAr in $intArr )
  	{
  		int $isFound = false;
  		for( $resut in $resuts )
  		{
  			if( $intAr == $resut )
  			{
  				$isFound = true;
  				break;
  			}
  		}
  		if( $isFound == false )
  			$resuts[size($resuts)] = $intAr;
  	}
  
  	return $resuts;
  }
  

HTML Code:
intArrayRemoveDuplicates( {5, 5, 65, 65, 33, 22, 1} )



global proc float[] floatArrayRemoveDuplicates( float $floatArr[] )
 {
 	float $resuts[];
 
 	for( $floatAr in $floatArr )
 	{
 		int $isFound = false;
 		for( $resut in $resuts )
 		{
 			if( $floatAr == $resut )
 			{
 				$isFound = true;
 				break;
 			}
 		}
 		if( $isFound == false )
 			$resuts[size($resuts)] = $floatAr;
 	}
 
 	return $resuts;
 }

HTML Code:
floatArrayRemoveDuplicates( {1.0, 1.0, 2.5, 3.2, 2.5, 1.0, 58.88} )


Thank You,
nn
 
  01 January 2011
nice! could even be more elegant with also useful isInArray functions:

global proc float[] floatArrayRemoveDuplicates( float $array[] )
{
	float $resuts[];
	int $count = 0;
	
	for( $item in $array )
		if ( !isInFloatArray($item, $resuts) )
			$resuts[$count++] = $item;

	return $resuts;
}

global proc int isInFloatArray( float $value, float $array[] )
{
	for ( $item in $array )
		if ( $item == $value )
			return true;
	
	return false;
}
__________________
goodsoul.de
 
  01 January 2011
Given the limited precision of floats, the == operator on float isn't always what you want. Adding an optional tolerance value might be useful. I feel like there's something to that effect already in MEL somewhere, but I can't recall it.

Edit: Ah yes:

int	equivalentTol(float $a, float $b, float $tol)


Examples:
equivalentTol(0.0, 0.0005, 0.001);
   // Result : 1 //
   equivalentTol(0.0, 0.005, 0.001);
   // Result : 0 //

Last edited by Keilun : 01 January 2011 at 08:00 PM.
 
  01 January 2011
hmm ... true but I'd rather implement that in an additional function to keep the real thing slim.

maybe like:
global proc float[] floatArrayRemoveDupTol( float $array[] , float $tol )
{
	float $resuts[];
	int $count = 0;
	
	for( $item in $array )
		if ( !isInFloatArrayTol($item, $resuts, $tol) )
			$resuts[$count++] = $item;

	return $resuts;
}

global proc int isInFloatArrayTol( float $value, float $array[], float $tol )
{
	for ( $item in $array )
		if ( equivalentTol($item, $value, $tol) )
			return true;
	
	return false;
}

floatArrayRemoveDupTol({0.1, 0.10001, 0.2, 0.23}, 0.03);
// Result: 0.1 0.2 // 
__________________
goodsoul.de
 
  01 January 2011
Originally Posted by ewerybody: to keep the real thing slim...



    floatArrayRemoveDupTol({0.07, 0.1, 0.04}, 0.03);
    floatArrayRemoveDupTol({0.04, 0.1, 0.07}, 0.03);
     // Result: ??? // 

Last edited by denisT : 01 January 2011 at 04:29 AM.
 
  01 January 2011
ehmm... yes?
__________________
goodsoul.de
 
  01 January 2011
Originally Posted by denisT:

       floatArrayRemoveDupTol({0.07, 0.1, 0.04}, 0.03);
       floatArrayRemoveDupTol({0.04, 0.1, 0.07}, 0.03);
        // Result: ??? // 


i just want to say that the method might be not accurate but it has not to depend on order of array items.
the solution #1 is to sort a float array before the removing duplicates using tolerance.
but the method i use is to ROUND array values using some precision, and collect only unique after that:

  global proc float roundFloat (float $f, float $precision)
  {
  	$f /= $precision;
  	float $f1 = floor($f);
  	float $f2 = ceil($f);
  	float $v = (($f - $f1) > ($f2 - $f)) ? $f2 : $f1;
  	return ($v*$precision);
  }
  global proc int findFloatItem (float $item, float $array[])
  {
  	for ($k = 0; $k < size($array); $k++) if ($item == $array[$k]) return $k;
  	return -1;
  };
  global proc float[] uniqueRoundFloatArray (float $array[], float $precision)
  {
  	float $arr[], $i;
  	for ($item in $array)
  	{
  		$i = roundFloat($item, $precision);
  		if (findFloatItem($i,$arr) == -1) $arr[size($arr)] = $i;
  	}
  	return $arr;
 //    return (sort($arr)); // if you like
  }
  uniqueRoundFloatArray ({0.1, 0.10001, 0.2, 0.23}, 0.1);
  // Result:0.1 0.2//
  uniqueRoundFloatArray ({0.1, 0.10001, 0.2, 0.23}, 0.01);
  // Result:0.1 0.2 0.23//
  

Last edited by denisT : 01 January 2011 at 06:04 PM.
 
  01 January 2011
Okay, this is maybe a little bit overdone but it works:

global float $ffArray[] = {1.0, 2.3, 4.4, 99, 2.3, 4, 2.3}; 
float $sorted[] = python("import pymel.core as pm; list(set((pm.getMelGlobal(\"float[]\", \"$ffArray\"))))");
  print $sorted;
 
 
  01 January 2011
@denis: true but I wasn't asking for a uniquifier with tolerance ;] this just was an example for the closest way to go.

@haggi: wow! But this doesn't fix the tolerance thing or does it? I'm too scared to try
__________________
goodsoul.de
 
  01 January 2011
Originally Posted by ewerybody: @denis: true but I wasn't asking for a uniquifier with tolerance ;] this just was an example for the closest way to go.

i wasn't answering to you. i just tried to warn against using a shortest way rather than the right one.
 
  01 January 2011
Originally Posted by denisT: i wasn't answering to you.

thats right. You qouted me and then said something seeming unrelated ??? Instead of saying what the problem is. Which I understand as well: A tolerance might not be what you want: You might want to truncate the floats decimal places and check against that. Which is a more understandable way indeed!

I'm just saying that It was not my idea but Keiluns. I never needed a function like that.

But as I think about that I remember a very cool function Nathan gave me and I think giving the number of decimals to keep is even more obvious.:

global proc int nRound(float $input)
 {
 	return trunc($input + (0.5 * sign($input)) );
 }
 
 global proc float cutFloat(float $float, int $decimals)
 {
 	int $factor = pow(10,$decimals);
 	return ((float)nRound($float * $factor) / $factor);
 }
 
 global proc int isInFloatArray( float $value, float $array[] )
 {
 	for ( $item in $array )
 		if ( $item == $value )
 			return true;
 	
 	return false;
 }
 
 global proc float[] floatArrayRemoveDuplicates2( float $array[] , float $decimals )
{
	float $resuts[], $f;
	int $count = 0;

	for( $item in $array )
	{
		$f = cutFloat($item, $decimals);
		if ( !isInFloatArray($f, $resuts) )
			$resuts[$count++] = $f;
	}
	return $resuts;
}
 
 floatArrayRemoveDuplicates2({0.1, 0.10001, 0.2, 0.23}, 1);
 // Result:0.1 0.2//
 floatArrayRemoveDuplicates2({0.1, 0.10001, 0.2, 0.23}, 2);
 // Result:0.1 0.2 0.23//


The sorting thing I'd leave to the user. Putting a sort() around his stuff wouldn't be too much to ask I guess

$aFloatArray = {0.1, 0.10001, 0.23, 0.2, 0.79, 0.7, 0.71};
 floatArrayRemoveDuplicates2($aFloatArray, 1);
 // Result: 0.1 0.23 0.2 0.79 0.7 // 
 floatArrayRemoveDuplicates2(sort($aFloatArray), 1);
 // Result: 0.1 0.2 0.7 0.79 // 
 sort(floatArrayRemoveDuplicates2($aFloatArray, 1));
 // Result: 0.1 0.2 0.23 0.7 0.79 //
__________________
goodsoul.de

Last edited by ewerybody : 01 January 2011 at 05:06 PM.
 
  01 January 2011
If you wanted to cheat though:

float $floater[] = {12.0, 15.2, 15.21, 22.0, 86.062, 178.0, 12.01, 22.01};
   int $precision = 1;
   string $feeder = "";
   int $i = 0;
   for( $i = 0; $i <=(`size $floater` - 1); $i++) {
   	$feeder += $floater[$i] + ",";
   }
   float $result[] = python("list(set( [ round(float(x), " + $precision + ") for x in  [" + $feeder + "] ] ) )");
  print $result;
  


Or you could write it simply as straight python.
Cheers.
__________________
...everything will be fine, as long as nothing goes wrong...

Last edited by isoparmB : 01 January 2011 at 04:45 PM.
 
  01 January 2011
Originally Posted by isoparmB: Or you could write it simply as straight python.
hehe yea so true.
__________________
goodsoul.de
 
Thread Closed share thread



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
CGSociety
Society of Digital Artists
www.cgsociety.org

Powered by vBulletin
Copyright 2000 - 2006,
Jelsoft Enterprises Ltd.
Minimize Ads
Forum Jump
Miscellaneous

All times are GMT. The time now is 08:09 AM.


Powered by vBulletin
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.