首页 > 解决方案 > 将数字划分为用户表单标签中显示的唯一排序数字

问题描述

我想将数字分成唯一的排序数字。例如,数字可以是 127425,我想要 12457 作为结果,这意味着已排序并删除了重复项。我认为最好的例子是解释:

+---------+--------+
| Number  | Result |
+---------+--------+
| 127425  | 12457  |
+---------+--------+
| 2784425 | 24578  |
+---------+--------+
| 121     | 12     |
+---------+--------+
| 22222   | 2      |
+---------+--------+
| 9271    | 1279   |
+---------+--------+

最长的结果只能是 123456789。

我不认为我们需要一个数组(没有分隔符),但使用子字符串可能会完成这项工作。我只是不知道从哪里开始,因此没有代码。

欢迎任何想法。谢谢。

标签: excelvbasortingduplicates

解决方案


替代较新的动态数组函数

喜欢上述不错的解决方案,考虑其他方法(通过Byte数组Filter()FilterXML()函数)总是一个挑战:

Function UniqueDigits(ByVal txt) As String
    Dim by() As Byte: by = txt
    Dim digits: digits = Array(49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 0) ' equalling Asc values
'a) create 1-based 1-dim array with digit positions
    Dim tmp: tmp = Filter(Application.Match(by, digits, 0), 11, False)
'b) get uniques
    tmp = Uniques(tmp)
'c) sort it (don't execute before getting uniques)
    BubbleSort tmp
'd) return function result
    UniqueDigits = Join(tmp, "")
End Function
Function Uniques(arr)
'Note: using FilterXML() available since vers. 2013+
    Dim content As String       ' replacing "10" referring to zero indexed as 10th digit
    content = Replace("<t><s>" & Join(arr, "</s><s>") & "</s></t>", "10", "0")
    arr = WorksheetFunction.FilterXML(content, "//s[not(preceding::*=.)]")
    Uniques = Application.Transpose(arr)
End Function
Sub BubbleSort(arr)
    Dim cnt As Long, nxt As Long, temp
    For cnt = LBound(arr) To UBound(arr) - 1
        For nxt = cnt + 1 To UBound(arr)
            If arr(cnt) > arr(nxt) Then
                temp = arr(cnt)
                arr(cnt) = arr(nxt)
                arr(nxt) = temp
            End If
        Next nxt
    Next cnt
End Sub

进一步的提示:-) tl;dr

...解释

a) 如何将字符串转换为数字数组,b) 如何通过 FilterXML 而不是字典来获取唯一性 c)(执行 BubbleSort 无需进一步解释)。

ad a)获取纯数字数组的棘手方法将 一串数字转换为单个字符的数组可能需要一些解释。

  1. 一个字符串(这里txt)可以很容易地通过 分配给一个字节数组Dim by() As Byte: by = txt。(请注意,经典字符将在字节数组中由一Asc表示,其中第二个值主要是0;因此 digit1由 49 和 0、502和 0 到957 和 0 表示)。

数字定义在从~>49 到~>57的基于 1 的Asc值数组中,然后是第 10 项~>48,最后是与每个第二个字节对相关的第 11 项的值。190Asc0

Dim digits: digits = Array(49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 0) ' equalling Asc values
  1. 通常,该Match()函数会搜索指定项以获取其在数组中的相对位置(此处digits),并将通过以下语法执行:``.

MATCH( lookup_value ,lookup_array, [match_type]) 其中lookup_value参数可以是一个值(数字、文本或逻辑值)或对数字、文本或逻辑值的单元格引用。

一个未记录的特性是,例如2在 lookup_array 中digits搜索 ,Application.Match(2, digits,0)您可以使用字节数组作为第一个参数,用作基于 1 的数组模式,其中 VBA 用它们在数字数组中找到的位置Asc替换当前值。

Application.Match(by, digits, 0)

最后,负过滤通过以下方式删除伴随Asc 0值(11加参数False

Dim tmp: tmp = Filter(Application.Match(by, digits, 0), 11, False)

ad b)通过 FilterXML 获取唯一性

WorksheetFunction.FilterXML该方法需要两个字符串参数的帮助参考

FilterXML(XMLContentString, XPathQueryString)

第一个参数不引用文件,但需要以根节点 (DocumentElement) 开头的有效(“格式良好”)XML 文本字符串,该字符串与以封闭<html>...</html>标记对开头的 html 结构大致相当。

因此,表示例如数字的格式良好的内容字符串121可以是:

<t>
    <s>1</s>
    <s>2</s>
    <s>1</s>
</t>

第二个参数(限制为 1024 个字符)必须是有效的XPath 查询字符串,如下所示

"//s[not(preceding::*=.)]"

其中双斜杠//允许查找s任何层次结构级别的节点,并且在它之前没有任何*具有相同值内容的节点的情况下=.

推荐读数

@RonRosenfeld 是涵盖该方法的众多答案的先驱作者,FilterXML例如拆分字符串单元...。

@JvDV 在使用 FilterXML 从字符串中提取子字符串中写了一个近乎百科全书的概述。


推荐阅读