Distinct list

Hello guys,

I got a question for specifying multiple lists.
In general, I want to specify how many different lists in a tree and return them.
For instance, I got one tree contains 4 lists of integers

list1 = {4,2,1};
list2 = {2,1,0};
list3 = {4,2,1};
list4 = {5,2,1};

There are only 3 types of lists(list1 is equal to list3). The sequences of the integers in the list should be the same otherwise it cannot be regarded as the same list.

Eventually, it should give me only 3 types: {4,2,1} , {2,1,0} , {5,2,1}

I’ve tried writing a C# script to deal with this problem but it doesn’t work. If anyone can help me with this I’ll be really appreciated! Thank you!

DistinctMethod1.gh (11.3 KB)

private void RunScript(DataTree<int> x, ref object A)
{

var result = new DataTree<int>();
var hashes = new List<int>();
foreach(var path in x.Paths)
{
  var list = x.Branch(path);
  int hash = list.Count;
  foreach(var i in list)
    hash ^= i;
  if(hashes.Contains(hash)){
    Print(string.Format("Path {0} already exists.", path));
  }else{
    hashes.Add(hash);
    result.AddRange(list, path);
  }
}
A = result;

}

I think it’s not technically perfect, but it’s highly unlikely to fail in your case of use.

DistinctMethod1.gh (12.4 KB)

You can do this quite easily in Python by using sets - not sure how you’d convert to C#!

It is quite easy to do even in GH, the hard part is to deal with trees.

1 Like

distinct.gh (5.9 KB)

  private void RunScript(DataTree<int> lists, ref object distinctLists)
  {
    var dt = new DataTree<int>();
    var hashSet = new HashSet<List<int>>(lists.Branches, new SameList());
    var index = 0;
    foreach(var it in hashSet)
    {
      dt.AddRange(it, new GH_Path(index));
      ++index;
    }
    distinctLists = dt;
  }

  private class SameList : IEqualityComparer<List<int>>
  {
    public int GetHashCode(List<int> list)
    {
      var hash = 0;
      for(var i = 0;i < list.Count;i++)
      {
        hash ^= list[i];
        hash <<= 1;
      }
      return hash;
    }

    public bool Equals(List<int> x, List<int> y)
    {
      if(x.Count != y.Count) return false;
      for(var i = 0;i < x.Count;i++)
      {
        if(x[i] != y[i]) return false;
      }
      return true;
    }
  }

I guess it depends if the tree structure is important or not. If not, it can be compressed even further:

image

3 Likes

Thanks you guys!
you guys are amazing!<3

Hello,

it works in integers, I’d like to know if it is possible to operate in double?

Thanks!

Hello,
i it possible to work with double/float?

Thank you

private void RunScript(DataTree<double> lists, ref object distinctLists)
        {
            var dt = new DataTree<double>();
            var hashSet = new HashSet<List<double>>(lists.Branches, new SameList());
            var index = 0;
            foreach (var it in hashSet)
            {
                dt.AddRange(it, new GH_Path(index));
                ++index;
            }
            distinctLists = dt;
        }

        private class SameList : IEqualityComparer<List<double>>
        {
            public int GetHashCode(List<double> list)
            {
                var hash = 0;
                for (var i = 0; i < list.Count; i++)
                {
                    hash ^= list[i].GetHashCode();
                    hash <<= 1;
                }
                return hash;
            }

            public bool Equals(List<double> x, List<double> y)
            {
                if (x.Count != y.Count) return false;
                for (var i = 0; i < x.Count; i++)
                {
                    if (Math.Abs(x[i] - y[i]) > RhinoMath.ZeroTolerance) return false;
                }
                return true;
            }
        }
1 Like