Powershell - 在数组中搜索是否存在哈希表中的值

Powershell - Search an array for presence of value from a hash table

提问人:Jay_C_NNJ 提问时间:11/10/2023 最后编辑:Jay_C_NNJ 更新时间:11/11/2023 访问量:41

问:

我正在将标题行从 Excel 电子表格加载到数组中,并需要将其与每个值具有多个键条目的哈希表进行比较。我需要能够为我正在搜索的每个列提供不同的变体。 数组包含标题行 (人名、Customer_Account_Number、电力公司、公司名称、Service_Address_1、Service_City、Service_State、Service_Zip、电话号码)

我需要像这样设置我的变量:

$nameColumn = 1 $companyColumn = 4


$headers = @()
for ($col = 1; $col -le $worksheet.UsedRange.Columns.Count; $col++) {
    $headers += $($worksheet.Cells.Item(1, $col).Text)
}

$headerMappings = @{
     "name"               = "Name";
     "person name"        = "Name";
     "contact Name"       = "Name"
     "company name"       = "Company"
     "service_address_1"  = "Address"
     "address"            = "Address"
     "service_city"       = "City"
     "city"               = "City"
     "service_state"      = "State"
     "state"              = "State"
     "service_zip"        = "Zip"
     "zip"                = "Zip"
     "phone number"       = "Phone"
     "phone"              = "Phone"
}

# Get column indices for specific field names using headerMappings

$nameColumn    = $headers.IndexOf($headerMappings["Name"])
$companyColumn = $headers.IndexOf($headerMappings["Company"])
$addressColumn = $headers.IndexOf($headerMappings["Address"])
$cityColumn    = $headers.IndexOf($headerMappings["City"])
$stateColumn   = $headers.IndexOf($headerMappings["State"])
$zipColumn     = $headers.IndexOf($headerMappings["Zip"])
$phoneColumn   = $headers.IndexOf($headerMappings["Phone"])

PowerShell 哈希表

评论

2赞 Santiago Squarzon 11/10/2023
您正在将哈希表与数组进行比较,除此之外,它不清楚包含什么,也不清楚您想要的最终结果是什么$headers
1赞 Jay_C_NNJ 11/10/2023
谢谢圣地亚哥,我更新了帖子以使其更清晰。
2赞 Mathias R. Jessen 11/10/2023
如果 excel 标题包含多个匹配项,例如同时包含 a 和列的工作表,该怎么办?你想选哪一个?contact Namename
1赞 Jay_C_NNJ 11/10/2023
问得好。我想我想在出现错误时停止该过程,因为我们需要更仔细地查看输入文件。它应该只包含每种类型的一列(名称/地址/城市...等)

答:

1赞 mklement0 11/10/2023 #1

$headers是一个数组,是一个哈希表$headerMappings

我建议采用两步法

  • 创建一个映射标头名称数组,用于翻译;例如,翻译为 .$headerMappingsservice_address_1Address

  • 然后,根据映射的标头名称数组进行查找。.IndexOf()

# Sample input array.
$headers =  'person name', 'service_state', 'phone', 'service_address_1'

$headerMappings = @{
     "name"               = "Name"
     "person name"        = "Name"
     "contact Name"       = "Name"
     "company name"       = "Company"
     "service_address_1"  = "Address"
     "address"            = "Address"
     "service_city"       = "City"
     "city"               = "City"
     "service_state"      = "State"
     "state"              = "State"
     "service_zip"        = "Zip"
     "zip"                = "Zip"
     "phone number"       = "Phone"
     "phone"              = "Phone"
}

# Translate the headers to their mapped names.
# Note: This assumes that all headers names are covered by the hashtable.
$mappedHeaders = @($headers | ForEach-Object { $headerMappings[$_] })

# Get column indices based on the array of *mapped* header names.
# Note: .IndexOf() is *case-sensitive*.
# ...
$addressColumn = $mappedHeaders.IndexOf('Address') # -> 3

请注意,如果给定的标头数组包含多个映射到哈希表中相同名称的标头,则上述将仅报告第一个此类标头的索引。


至于你试过的

$headerMappings["Name"]

"Name"是哈希表条目,而不是;它被用于多个条目中,即带有键 、 和 的条目。"name""person_name""contact_Name"

因此,表达式的计算结果可预测为 ,并且调用可预测地返回(以指示输入对象不是数组的一部分)。$null.IndexOf()-1

如果你想在没有中间帮助程序数组的情况下执行此操作(如上所示),则必须执行以下操作,但是,这是低效的,因为它涉及在整个数组中搜索每个索引:

$headers.IndexOf(
  $headers.Where({ $headerMappings[$_] -eq 'Address' }, 'First')[0]
)
1赞 mklement0 11/10/2023 #2

另一个答案建立在您自己的方法之上,即将列(标题)索引存储在不同的变量中。

另一种方法是构建另一个哈希表,将映射的标题映射到列索引。

$headerIndexMappings = @{}
$i = 0
$headers | ForEach-Object {
  $headerIndexMappings[$headerMappings[$_]] = $i++
}

然后,您可以使用映射的标头名称访问生成的哈希表,以检索原始标头的索引;例如,或者 - 更简单地说 - 另一个答案中样本数组的产量。$headerIndexMappings['Address']$headerIndexMappings.Address3$headers

除了不需要为每个映射标头定义单独的变量之外,这种方法的优点是查找不区分大小写(就像 PowerShell 的哈希表通常一样),因此也可以使用。$headerIndexMappings.address