【问题标题】:Compare each element in an array to each other比较数组中的每个元素
【发布时间】:2010-12-16 23:19:03
【问题描述】:

我需要比较一个一维数组,因为我需要将数组的每个元素与其他元素进行比较。该数组包含从最长到最短排序的字符串列表。数组中没有 2 个项目是相等的,但是会有相同长度的项目。目前我正在进行 N*(N+1)/2 比较(1278 亿次),并且我正在尝试减少所有比较的数量。

我已经实现了一个功能,基本上说:如果字符串的长度差异超过 x%,那么不要打扰他们不相等,并且他下面的其他人也不相等,所以只需打破循环并继续下一个元素。

我目前正试图通过以下方式进一步减少这种情况:如果元素 A 与元素 C 和 D 匹配,那么元素 C 和 D 也会匹配,因此不必费心检查它们(即跳过该操作)。这是我所考虑的,因为我目前不知道允许我这样做的数据结构。

这里的问题是:有人知道这样的数据结构吗?或者有谁知道我可以如何进一步减少我的比较?

我目前的实现估计需要 3.5 天才能在 10 小时的时间窗口内完成(即它太长了),我剩下的唯一选择是减少执行时间,这可能或不可能,或者分发跨越数十个系统的工作负载,这可能不切实际。

更新:我的错。将单词equal 替换为与with 密切匹配。我正在计算莱文斯坦距离

这个想法是找出数组中是否有其他字符串与数组中的每个元素紧密匹配。输出是密切相关的字符串的数据库映射。

这是该方法的部分代码。在执行此代码块之前,有代码将项目加载到数据库中。

    public static void RelatedAddressCompute() {
        TableWipe("RelatedAddress");

        decimal _requiredDistance = Properties.Settings.Default.LevenshteinDistance;

        SqlConnection _connection = new SqlConnection(Properties.Settings.Default.AML_STORE);
        _connection.Open();

        string _cacheFilter = "LevenshteinCache NOT IN ('','SAMEASABOVE','SAME')";

        SqlCommand _dataCommand = new SqlCommand(@"
        SELECT
            COUNT(DISTINCT LevenshteinCache)
        FROM
            Address
        WHERE 
            " + _cacheFilter + @"
        AND
            LEN(LevenshteinCache) > 12", _connection);
        _dataCommand.CommandTimeout = 0;
        int _addressCount = (int)_dataCommand.ExecuteScalar();

        _dataCommand = new SqlCommand(@"
        SELECT 
            Data.LevenshteinCache,
            Data.CacheCount
        FROM            
            (SELECT
                DISTINCT LevenshteinCache,
                COUNT(LevenshteinCache) AS CacheCount
            FROM
                Address
            WHERE 
                " + _cacheFilter + @"
            GROUP BY 
                LevenshteinCache) Data
        WHERE 
            LEN(LevenshteinCache) > 12
        ORDER BY 
            LEN(LevenshteinCache) DESC", _connection);
        _dataCommand.CommandTimeout = 0;
        SqlDataReader _addressReader = _dataCommand.ExecuteReader();

        string[] _addresses = new string[_addressCount + 1];
        int[] _addressInstance = new int[_addressCount + 1];
        int _itemIndex = 1;
        while (_addressReader.Read()) {
            string _address = (string)_addressReader[0];
            int _count = (int)_addressReader[1];
            _addresses[_itemIndex] = _address;
            _addressInstance[_itemIndex] = _count;
            _itemIndex++;
        }

        _addressReader.Close();
        decimal _comparasionsMade = 0;
        decimal _comparisionsAttempted = 0;
        decimal _comparisionsExpected = (decimal)_addressCount * ((decimal)_addressCount + 1) / 2;
        decimal _percentCompleted = 0;
        DateTime _startTime = DateTime.Now;
        Parallel.For(1, _addressCount, delegate(int i) {
            for (int _index = i + 1; _index <= _addressCount; _index++) {
                _comparisionsAttempted++;
                decimal _percent = _addresses[i].Length < _addresses[_index].Length ? (decimal)_addresses[i].Length / (decimal)_addresses[_index].Length : (decimal)_addresses[_index].Length / (decimal)_addresses[i].Length;
                if (_percent < _requiredDistance) {
                    decimal _difference = new Levenshtein().threasholdiLD(_addresses[i], _addresses[_index], 50);
                    _comparasionsMade++;
                    if (_difference <= _requiredDistance) {
                        InsertRelatedAddress(ref _connection, _addresses[i], _addresses[_index], _difference);
                    }
                }
                else {
                    _comparisionsAttempted += _addressCount - _index;
                    break;
                }
            }
            if (_addressInstance[i] > 1 && _addressInstance[i] < 31) {
                InsertRelatedAddress(ref _connection, _addresses[i], _addresses[i], 0);
            }
            _percentCompleted = (_comparisionsAttempted / _comparisionsExpected) * 100M;
            TimeSpan _estimatedDuration = new TimeSpan((long)((((decimal)(DateTime.Now - _startTime).Ticks) / _percentCompleted) * 100));
            TimeSpan _timeRemaining = _estimatedDuration - (DateTime.Now - _startTime);
            string _timeRemains = _timeRemaining.ToString();
        });
    }

InsertRelatedAddress 是一个更新数据库的函数,数组中有500,000项。

【问题讨论】:

  • 根据定义,一对长度不等的字符串不应彼此相等。你为什么要处理 X% 的长度差异?此外,发布您当前算法的代码或伪代码会很棒。
  • 请澄清:你想产生什么输出?

标签: c# arrays


【解决方案1】:

好的。有了更新的问题,我认为它更有意义。您想找到 Levenshtein 距离小于预设距离的字符串对。我认为关键是您不要比较每一组字符串,而是依靠 Levenshtein distance 的属性来搜索预设限制内的字符串。答案涉及计算可能变化的树。也就是说,计算距离

看起来像这里发布的问题:Finding closest neighbour using optimized Levenshtein Algorithm

【讨论】:

    【解决方案2】:

    需要更多信息。你想要的结果是什么?您是否要计算所有唯一字符串的数量?您声明您想查看 2 个字符串是否相等,并且如果“它们的长度相差 x%,那么不要打扰它们不相等”。你为什么要检查 x% 的长度约束?如果您要检查它们是否相等,它们的长度必须相同。 我怀疑您正在尝试与确定完全匹配稍有不同的东西,在这种情况下我需要更多信息。 谢谢 尼尔

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-13
      • 1970-01-01
      • 2017-10-30
      • 1970-01-01
      • 2016-06-19
      • 1970-01-01
      相关资源
      最近更新 更多