从区域中的单元格中读取所有唯一值,并从中创建逗号分隔的字符串



>我编写了以下函数来从范围内的单元格中读取所有唯一值并从中创建逗号分隔的字符串?有没有更好、更简单的方法可以做到这一点?

Private Sub CsvUniqueValues(r As Excel.Range)
    Dim c As Excel.Range
    Dim s As String = ""
    For Each c In r.Cells
        If ExcelApp.WorksheetFunction.CountIf(r, c.Value) = 1 Then
            s = s & ","
        End If
    Next
    If s.Length > 0 Then
        s = s.Substring(0, s.Length - 1)
    End If
End Sub

可以使用 LINQ 获取仅包含唯一值的列表,如下所示:

Dim uniqueValues As IEnumerable = r.Cells.Where(Function(x) ExcelApp.WorksheetFunction.CountIf(r, x.Value) = 1))

然后,可以使用 LINQ 将所有这些唯一值转换为字符串:

Dim uniqueStrings As IEnumerable(Of String) = uniqueValues.Select(Of String)(Function(x) x.ToString())

然后,可以使用 LINQ 将结果列表转换为数组:

Dim uniqueArray() As String = uniqueStrings.ToArray()

然后,您可以使用 String.Join 方法将它们合并为单个 CSV 字符串:

Dim csv As String = String.Join(",", uniqueArray)

当然,您可以在单个命令中完成所有这些操作,如下所示:

Dim csv As String = String.Join(",", 
    r.Cells.Where(Function(x) ExcelApp.WorksheetFunction.CountIf(r, x.Value) = 1))
    .Select(Of String)(Function(x) x.ToString())
    .ToArray())

然而,问题是你是否会称之为"更容易"。 LINQ 很有用,因为它使代码更易于读取和编写,但是当代码走得太远时,它的可读性会降低,从而违背使用它的目的。 至少,为了使您的代码更清晰,我会将第一部分移动到命名函数中,以便它更加自我记录:

Public Function GetUniqueCellValuesAsString(r As Excel.Range) As IEnumerable(Of String)
    Return r.Cells.Where(
        Function(x) ExcelApp.WorksheetFunction.CountIf(r, x.Value) = 1))
        .Select(Of String)(Function(x) x.ToString())
End Function

然后,您可以像这样构建CSV字符串:

Dim csv As String = String.Join(",", GetUniqueCellValuesAsString(r).ToArray())

我会使用collection对象。由于集合只能包含唯一值,因此尝试将所有输入数据添加到集合将生成唯一值数组。以下修改允许CsvUniqueValues从任何给定范围内的值返回逗号分隔的字符串。

'Test function and return result in MsgBox
Sub ReturnUnique()
    MsgBox CsvUniqueValues(Selection)
End Sub
'Function will return csv-string from input range
Function CsvUniqueValues(r As Range) As String
    Dim Cell As Range
    Dim i As Integer
    Dim DistCol As New Collection
    Dim s As String
    'Add all distinct values to collection
    On Error Resume Next
    For Each Cell In r
        DistCol.Add Cell.Value, Cell.Value
    Next Cell
    On Error GoTo 0
    'Write collection to comma seperated list
    For i = 1 To DistCol.Count
        s = s & DistCol.Item(i) & "; "
    Next i
    s = Left(s, Len(s) - 2)
    CsvUniqueValues = s
End Function

最新更新