Skip to content

List.groupBy produces TreeMap with duplicate keys #292

@rsmilyanov

Description

@rsmilyanov

Hi guys,

I am having the following property based test:

import fj.P2;
import fj.data.List;
import fj.data.TreeMap;
import fj.test.Arbitrary;
import fj.test.Property;
import fj.test.reflect.CheckParams;
import fj.test.runner.PropertyTestRunner;
import org.junit.runner.RunWith;

import java.util.Map;

import static fj.P.p;
import static fj.test.Property.prop;
import static java.util.stream.Collectors.*;

/**
 * Created by rsmilyanov on 20.07.16.
 */

@RunWith(PropertyTestRunner.class)
public class Foo
{
    @CheckParams(minSuccessful = 1000 )
    public Property foo()
    {

        return Property.property(Arbitrary.arbList(Arbitrary.arbString), list ->
        {
            // prepare list of P2<String, String> which has each ten times each random string as P2<random string, int from 1 to 10>
            final List.Buffer<P2<String, String>> data = List.Buffer.empty();
            list.foreachDoEffect(s -> List.range(1, 10).forEach(i -> data.snoc(p(s, String.valueOf(i)))));

            final List<P2<String, String>> testData = data.toList();

            // the same result will be returned if groupBy is called with Ord.hashEqualsOrd() 
            final TreeMap<String, List<String>> fjGroupBy = testData.groupBy(w -> w._1(), w -> w._2());
            final Map<String, java.util.List<String>> javaGroupBy =
                    testData.toJavaList().stream().collect(groupingBy(w -> w._1(), mapping(P2::_2, toList())));

            final boolean keySizeEquals = fjGroupBy.keys().length() == javaGroupBy.keySet().size();
            if (!keySizeEquals)
            {
                System.out.println("jf groupBy key set length " + fjGroupBy.keys().length());
                System.out.println("java groupBy key set length " + javaGroupBy.keySet().size());
                return prop(false);
            }

            for (P2<String, List<String>> entry : fjGroupBy.toList())
            {
                final boolean sizeEqual = javaGroupBy.get(entry._1()).size() == entry._2().length();

                final boolean fjListContainsAllJavaEntries = entry._2().forall(w -> javaGroupBy.get(entry._1()).contains(w));

                final boolean javaListContainsAllFjEntries = javaGroupBy.get(entry._1()).stream().allMatch(w -> entry._2().find(w1 -> w.equals(w1)).isSome());

                if (!sizeEqual || !fjListContainsAllJavaEntries || !javaListContainsAllFjEntries)
                {
                    System.out.println("fj entry " + entry + " java util entry " + javaGroupBy.get(entry._1()));
                    return prop(false);
                }
            }

            return prop(true);
        });

    }

}

If I pass Ord.stringOrd into groupBy function I get correct results. I expected that since my test data is java.lang.String, that I will get one and the same results for Ord.hashOrd(), Ord.hashEqualsOrd() and Ord.stringOrd. Am I wrong?

Thanks,
Rado

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions