हैश के माध्यम से लूपिंग करना, या पावरशेल में एक सरणी का उपयोग करना


96

मैं BCP के साथ SQL सर्वर से तालिकाओं के एक सेट को निकालने के लिए इस (सरलीकृत) कोड का उपयोग कर रहा हूं ।

$OutputDirectory = "c:\junk\"
$ServerOption =   "-SServerName"
$TargetDatabase = "Content.dbo."

$ExtractTables = @(
    "Page"
    , "ChecklistItemCategory"
    , "ChecklistItem"
)

for ($i=0; $i -le $ExtractTables.Length – 1; $i++)  {
    $InputFullTableName = "$TargetDatabase$($ExtractTables[$i])"
    $OutputFullFileName = "$OutputDirectory$($ExtractTables[$i])"
    bcp $InputFullTableName out $OutputFullFileName -T -c $ServerOption
}

यह बहुत अच्छा काम करता है, लेकिन अब कुछ तालिकाओं को विचारों के माध्यम से निकालने की आवश्यकता है, और कुछ नहीं। इसलिए मुझे डेटा संरचना कुछ इस तरह चाहिए:

"Page"                      "vExtractPage"
, "ChecklistItemCategory"   "ChecklistItemCategory"
, "ChecklistItem"           "vExtractChecklistItem"

मैं हैश देख रहा था, लेकिन मुझे कुछ भी नहीं मिल रहा है कि कैसे हैश के माध्यम से लूप किया जाए। यहां क्या करना सही होगा? शायद बस एक सरणी का उपयोग करें, लेकिन दोनों मूल्यों के साथ, अंतरिक्ष द्वारा अलग किया गया?

या मैं कुछ स्पष्ट याद कर रहा हूँ?

जवाबों:


108

ईसाई का जवाब अच्छी तरह से काम करता है और दिखाता है कि आप GetEnumeratorविधि का उपयोग करके प्रत्येक हैश टेबल आइटम के माध्यम से कैसे लूप कर सकते हैं । आप keysसंपत्ति का उपयोग करके भी लूप कर सकते हैं। यहाँ एक उदाहरण है कि कैसे:

$hash = @{
    a = 1
    b = 2
    c = 3
}
$hash.Keys | % { "key = $_ , value = " + $hash.Item($_) }

आउटपुट:

key = c , value = 3
key = a , value = 1
key = b , value = 2

मैं किसी अन्य क्रम में हैश की गणना कैसे कर सकता हूं? उदाहरण के लिए, जब मैं आरोही क्रम में इसकी सामग्री प्रिंट करना चाहता हूं (यहाँ एक ... b ... c)। क्या यह भी संभव है?
LPrc

5
$hash.Item($_)इसके बजाय क्यों $hash[$_]?
अल्वारेज़

1
@LPrc ऐसा करने के लिए Sort-Object विधि का उपयोग करता है। यह लेख इसकी बहुत अच्छी व्याख्या करता है: Technet.microsoft.com/en-us/library/ee692803.aspx
chazbot7

4
तुम भी बस का उपयोग कर सकते हैं $hash.$_
टीएनटी

1
यह तरीका काम नहीं करता है यदि हैशटेबल में कुंजी = 'की' है।
बोरिस निकितिन

197

स्क्रिप्ट के लिए शॉर्टहैंड को प्राथमिकता नहीं दी जाती है; यह कम पठनीय है। % {} ऑपरेटर को शॉर्टहैंड माना जाता है। यहाँ यह पठनीयता और पुन: प्रयोज्य के लिए एक स्क्रिप्ट में कैसे किया जाना चाहिए:

परिवर्तनीय सेटअप

PS> $hash = @{
    a = 1
    b = 2
    c = 3
}
PS> $hash

Name                           Value
----                           -----
c                              3
b                              2
a                              1

विकल्प 1: GetEnumerator ()

नोट: व्यक्तिगत प्राथमिकता; सिंटेक्स पढ़ना आसान है

GetEnumerator () विधि दिखाए गए अनुसार की जाएगी:

foreach ($h in $hash.GetEnumerator()) {
    Write-Host "$($h.Name): $($h.Value)"
}

आउटपुट:

c: 3
b: 2
a: 1

विकल्प 2: कुंजी

कुंजी विधि को दिखाया गया है:

foreach ($h in $hash.Keys) {
    Write-Host "${h}: $($hash.Item($h))"
}

आउटपुट:

c: 3
b: 2
a: 1

अतिरिक्त जानकारी

अपने हैशटेबल को छाँटने में सावधानी बरतें ...

सॉर्ट-ऑब्जेक्ट इसे एक सरणी में बदल सकता है:

PS> $hash.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Hashtable                                System.Object


PS> $hash = $hash.GetEnumerator() | Sort-Object Name
PS> $hash.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

यह और अन्य PowerShell लूपिंग मेरे ब्लॉग पर उपलब्ध हैं।


3
पठनीयता के लिए यह एक और पसंद है, विशेष रूप से मेरे जैसे पावरसैल डेवलपर्स को समर्पित नहीं करने के लिए।
AIBMer

1
मैं मानता हूं कि यह तरीका पढ़ना आसान है और इसके बाद स्क्रिप्टिंग के लिए बेहतर है।
leinad13

2
एक तरफ पठनीयता, वर्टिगोराय के समाधान और एंडी के समाधान के बीच एक अंतर है। % {} के लिए एक उपनाम है ForEach-Object, जो foreachयहां दिए गए कथन से अलग है । ForEach-Objectयदि आप पहले से ही एक पाइपलाइन के साथ काम कर रहे हैं, तो पाइपलाइन का उपयोग और अधिक तेज़ हो सकता है। foreachबयान नहीं करता है, यह एक साधारण लूप है।
जेम्सक्यूमर्फी

4
@JamesQMurphy मैं ऊपर से @ andy-arismendi द्वारा प्रदान किए गए उत्तर को कॉपी और पेस्ट करता हूं; यह इस प्रश्न के लिए लोकप्रिय पाइपलाइन समाधान है। आपका बयान, जिसने मेरी रुचि को बढ़ाया, वह था ForEach-Object(उर्फ:) की %{}तुलना में तेज foreach; मैंने दिखाया कि तेज नहीं है । मैं यह दिखाना चाहता था कि आपकी बात मान्य थी या नहीं; क्योंकि मैं, ज्यादातर लोगों को, जैसे ही मेरा कोड संभव हो उतना तेज चलने के लिए। अब, आपका तर्क समानांतर में नौकरियों को चलाने के लिए बदल रहा है (संभवतः कई कंप्यूटर / सर्वर का उपयोग करके) ... जो निश्चित रूप से एक ही धागे से श्रृंखला में नौकरी चलाने से तेज है। चीयर्स!
वर्टिगोरे

1
@JamesQMurphy मुझे यह भी लगता है कि शक्तियां उस पारंपरिक लाभ का पालन करती हैं, जो आपको कई प्रक्रियाओं के बीच डेटा धाराओं को पाइप करने पर मिलने वाले गोले से मिलता है: आप सरल तथ्य से प्राकृतिक समानता प्राप्त करते हैं कि प्रत्येक पाइपलाइन चरण एक स्वतंत्र प्रक्रिया है (बेशक, एक बफर नाली है और अंत में पूरी पाइपलाइन इसकी सबसे धीमी प्रक्रिया जितनी धीमी होती है)। यह एक पाइपलाइन प्रक्रिया होने से भिन्न है जो कई थ्रेड्स को स्वयं करने का निर्णय लेती है, जो पूरी तरह से प्रक्रिया के कार्यान्वयन विवरणों पर निर्भर है।
जोहान बोले

8

आप इसे एक चर के बिना भी कर सकते हैं

@{
  'foo' = 222
  'bar' = 333
  'baz' = 444
  'qux' = 555
} | % getEnumerator | % {
  $_.key
  $_.value
}

यह मुझे एक "ForEach-Object: पैरामीटर को प्रोसेस नहीं कर सकता है"। सिस्टम के "getEnumerator" मान को "System.String" टाइप करने के लिए "System.Management.Automation.ScriptBlock"
luis.espinal

6

एक हैश के माध्यम से पाशन के बारे में:

$Q = @{"ONE"="1";"TWO"="2";"THREE"="3"}
$Q.GETENUMERATOR() | % { $_.VALUE }
1
3
2

$Q.GETENUMERATOR() | % { $_.key }
ONE
THREE
TWO

5

यहाँ एक और त्वरित तरीका है, मूल्य प्राप्त करने के लिए हैश तालिका में एक इंडेक्स के रूप में कुंजी का उपयोग करना:

$hash = @{
    'a' = 1;
    'b' = 2;
    'c' = 3
};

foreach($key in $hash.keys) {
    Write-Host ("Key = " + $key + " and Value = " + $hash[$key]);
}

5

मैं एक पाइपलाइन के साथ एन्यूमरेटर विधि पर इस संस्करण को पसंद करता हूं, क्योंकि आपको फॉर्च में हैश तालिका का उल्लेख नहीं करना है (पावरशेल 5 में परीक्षण):

$hash = @{
    'a' = 3
    'b' = 2
    'c' = 1
}
$hash.getEnumerator() | foreach {
    Write-Host ("Key = " + $_.key + " and Value = " + $_.value);
}

आउटपुट:

Key = c and Value = 1
Key = b and Value = 2
Key = a and Value = 3

अब, यह जानबूझकर मूल्य पर क्रमबद्ध नहीं किया गया है, एन्यूमरेटर केवल वस्तुओं को रिवर्स ऑर्डर में लौटाता है।

लेकिन चूंकि यह एक पाइपलाइन है, मैं अब मूल्य पर गणनाकर्ता से प्राप्त वस्तुओं को सॉर्ट कर सकता हूं:

$hash.getEnumerator() | sort-object -Property value -Desc | foreach {
  Write-Host ("Key = " + $_.key + " and Value = " + $_.value);
}

आउटपुट:

Key = a and Value = 3
Key = b and Value = 2
Key = c and Value = 1

प्रगणक "किसी भी" क्रम में मूल्यों को वापस कर सकता है , क्योंकि यह बस अंतर्निहित कार्यान्वयन को पुनरावृत्त करता है। इस मामले में यह होता है कि रिवर्स ऑर्डर दिखाई दे । एक काउंटर-उदाहरण के लिए: $x = @{a = 1; z = 2}; $x.q = 3q, a, z के रूप में "ऑर्डर" किया जाता है।
user2864740


0

यदि आप PowerShell v3 का उपयोग कर रहे हैं, तो आप हैशटेबल के बजाय JSON का उपयोग कर सकते हैं, और इसे Convert-WJson के साथ किसी ऑब्जेक्ट में बदल सकते हैं :

@'
[
    {
        FileName = "Page";
        ObjectName = "vExtractPage";
    },
    {
        ObjectName = "ChecklistItemCategory";
    },
    {
        ObjectName = "ChecklistItem";
    },
]
'@ | 
    Convert-FromJson |
    ForEach-Object {
        $InputFullTableName = '{0}{1}' -f $TargetDatabase,$_.ObjectName

        # In strict mode, you can't reference a property that doesn't exist, 
        #so check if it has an explicit filename firest.
        $outputFileName = $_.ObjectName
        if( $_ | Get-Member FileName )
        {
            $outputFileName = $_.FileName
        }
        $OutputFullFileName = Join-Path $OutputDirectory $outputFileName

        bcp $InputFullTableName out $OutputFullFileName -T -c $ServerOption
    }

nb कमांड ConvertFrom-Json (और ऐक, ConvertTo-Json) है - बस डैश प्लेसमेंट को स्वैप करें।
atmarx
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.