/// <summary>
        /// Initializes a new instance of the <see cref="EnContactMatcher{Contact}"/> class.
        /// </summary>
        /// <param name="contacts">List of contacts.</param>
        /// <param name="extractContactFields">Delegate to extract contact fields from contact object.</param>
        /// <param name="config">Matcher configurations.</param>
        public EnContactMatcher(IList <Contact> contacts, Func <Contact, ContactFields> extractContactFields, MatcherConfig config)
            : base(config)
        {
            var targetEqualityComparer = new TargetEqualityComparer();
            HashSet <Target <Contact> > nameTargets  = new HashSet <Target <Contact> >(targetEqualityComparer);
            HashSet <Target <Contact> > aliasTargets = new HashSet <Target <Contact> >(targetEqualityComparer);

            this.nameMaxWindowSize  = 1;
            this.aliasMaxWindowSize = 1;

            for (int idx = 0; idx < contacts.Count; ++idx)
            {
                var contact = contacts[idx];
                var fields  = extractContactFields(contact);

                if (fields.Name != null)
                {
                    var name           = Preprocessor.PreProcess(fields.Name);
                    var nameVariations = this.AddNameVariations(contact, name, idx);

                    this.nameMaxWindowSize = Math.Max(this.nameMaxWindowSize, nameVariations.Count);

                    foreach (var variation in nameVariations)
                    {
                        nameTargets.Add(variation);
                    }
                }

                if (fields.Aliases != null)
                {
                    foreach (var aliasName in fields.Aliases)
                    {
                        var aliasVariations = this.AddNameVariations(contact, aliasName, idx);
                        this.aliasMaxWindowSize = Math.Max(this.aliasMaxWindowSize, aliasVariations.Count);
                        foreach (var variation in aliasVariations)
                        {
                            aliasTargets.Add(variation);
                        }
                    }
                }
            }

            this.nameFuzzyMatcher  = new EnHybridFuzzyMatcher <Target <Contact> >(nameTargets.ToArray(), this.Config.PhoneticWeightPercentage, (contact) => contact.Phrase);
            this.aliasFuzzyMatcher = new EnHybridFuzzyMatcher <Target <Contact> >(aliasTargets.ToArray(), this.Config.PhoneticWeightPercentage, (contact) => contact.Phrase);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="EnPlaceMatcher{Place}"/> class.
        /// </summary>
        /// <param name="places">The places to match against.</param>
        /// <param name="placeFieldsExtractor">Transform function from the user provided __Place__ object to __PlaceFields__, an intermediate representation used by the matcher. Defaults to the identity transform.</param>
        /// <param name="config">The matcher's configuration object.</param>
        public EnPlaceMatcher(IList <Place> places, Func <Place, PlaceFields> placeFieldsExtractor, MatcherConfig config)
            : base(config)
        {
            var targetEqualityComparer = new TargetEqualityComparer();
            var targets = new HashSet <Target <Place> >(targetEqualityComparer);

            this.maxWindowSize = 1;
            for (int idx = 0; idx < places.Count; ++idx)
            {
                var place  = places[idx];
                var fields = placeFieldsExtractor(place);

                var name    = string.Empty;
                var address = string.Empty;

                if (fields.Name != null)
                {
                    name = Preprocessor.PreProcess(fields.Name);
                }

                if (fields.Address != null)
                {
                    address = Preprocessor.PreProcess(fields.Address);
                }

                IList <Target <Place> > nameVariations = this.AddNameVariations(place, idx, name, address);
                this.maxWindowSize = Math.Max(this.maxWindowSize, nameVariations.Count);

                targets.UnionWith(nameVariations);

                if (fields.Types != null)
                {
                    foreach (var type in fields.Types)
                    {
                        var fieldVariations = this.AddNameVariations(place, idx, type);
                        this.maxWindowSize = Math.Max(this.maxWindowSize, fieldVariations.Count);
                        targets.UnionWith(fieldVariations);
                    }
                }
            }

            this.fuzzyMatcher = new EnHybridFuzzyMatcher <Target <Place> >(
                targets.ToArray(),
                this.Config.PhoneticWeightPercentage,
                (target) => target.Phrase);
        }