একটি হ্যাশ দিয়ে লুপ করা, বা পাওয়ারশেলের একটি অ্যারে ব্যবহার করে


98

বিসিপি সহ এসকিউএল সার্ভার থেকে টেবিলের একটি সেট বের করতে আমি এই (সরলীকৃত) কোড অব ব্যবহার করছি ।

$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"

আমি হ্যাশগুলির দিকে তাকিয়ে ছিলাম, তবে আমি কীভাবে একটি হ্যাশ দিয়ে লুপ করব সে সম্পর্কে কিছুই খুঁজে পাচ্ছি না। এখানে সঠিক জিনিস কি হবে? সম্ভবত একটি অ্যারে ব্যবহার করুন, তবে উভয় মান দিয়ে, স্থান দ্বারা পৃথক?

নাকি আমি স্পষ্ট কিছু মিস করছি?

উত্তর:


109

খ্রিস্টানের উত্তর ভালভাবে কাজ করে এবং দেখায় যে কীভাবে আপনি এই 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

আমি কীভাবে হ্যাশটিকে অন্য ক্রমে গণনা করতে পারি? উদাহরণস্বরূপ, যখন আমি এর সামগ্রীটি আরোহণের ক্রমে মুদ্রণ করতে চাই (এখানে একটি ... খ ... গ)। এটা কি সম্ভব?
এলপিআরসি

4
এর $hash.Item($_)বদলে কেন $hash[$_]?
alvarez

4
@LPrc এটি করতে বাছাই-অবজেক্ট পদ্ধতিটি ব্যবহার করুন। এই নিবন্ধটি সম্পর্কে এটির বেশ ভাল ব্যাখ্যা করেছে: টেকনেট.মাইক্রোসফট.ইন
ইউএস

4
আপনি এমনকি ব্যবহার করতে পারে $hash.$_
টিএনটি

4
এই পন্থাটি কার্যকর হয় না যদি হ্যাশটেবলে কী = 'কী' থাকে।
বোরিস নিকিটিন

200

শর্টহ্যান্ড স্ক্রিপ্টগুলির জন্য পছন্দনীয় নয়; এটি কম পাঠযোগ্য। % {} অপারেটরটিকে শর্টহ্যান্ড হিসাবে বিবেচনা করা হয়। পাঠযোগ্যতা এবং পুনঃব্যবহারযোগ্যতার জন্য এটি কীভাবে স্ক্রিপ্টে করা উচিত তা এখানে:

পরিবর্তনশীল সেটআপ

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

এটি এবং অন্যান্য পাওয়ারশেল লুপিং আমার ব্লগে উপলভ্য।


4
পাঠযোগ্যতার জন্য এটি আরও একটির মতো বিশেষত আমার মতো পাওয়ারশেল বিকাশকারীদের উত্সর্গ না করার জন্য।
anIBMer

4
আমি সম্মত হই যে এই পদ্ধতিটি পড়া সহজ এবং স্ক্রিপ্টিংয়ের পক্ষে সম্ভবত আরও ভাল ther
লিনাদ 13

4
পঠনযোগ্যতা একদিকে রেখে, ভার্টিগোয়ের সমাধান এবং অ্যান্ডির সমাধানের মধ্যে একটি পার্থক্য রয়েছে। % {for এর জন্য একটি উপনাম ForEach-Object, যা foreachএখানে বিবৃতিটির চেয়ে আলাদা । ForEach-Objectপাইপলাইনটি ব্যবহার করে, যদি আপনি ইতিমধ্যে পাইপলাইন নিয়ে কাজ করছেন তবে এটি আরও দ্রুত হতে পারে। foreachবিবৃতি না; এটি একটি সাধারণ লুপ
জেমসকিউমারফি

4
@ জেমসকিউ মুরফি আমি উপরের @ অ্যান্ডি-আরিস্মেন্দি প্রদত্ত উত্তরটি অনুলিপি করে আটকালাম; এটি এই প্রশ্নের জনপ্রিয় পাইপলাইন সমাধান। আপনার বক্তব্য, যা আমার আগ্রহের বিষয়টিকে উজ্জীবিত করেছিল, তা হ'ল ForEach-Object(ওরফে %{}:) এর চেয়ে দ্রুত foreach; আমি দেখিয়েছি যে দ্রুত হয় না । আপনার বক্তব্যটি বৈধ ছিল কি না তা আমি প্রদর্শন করতে চেয়েছিলাম; কারণ আমি, বেশিরভাগ লোকের মতোই আমার কোডটি যথাসম্ভব দ্রুত চালানো পছন্দ করি। এখন, আপনার যুক্তিটি সমান্তরালভাবে (চলমান একাধিক কম্পিউটার / সার্ভার ব্যবহার করে) কাজ চালুর দিকে বদলে যাচ্ছে ... অবশ্যই কোন এক থ্রেড থেকে সিরিজটিতে কাজ চালানোর চেয়ে দ্রুত is চিয়ার্স!
ভার্টিগোরে

4
@ জেমসকিউ মুর্ফি আমি আরও মনে করব যে পাওয়ারশেলগুলি প্রচলিত প্রক্রিয়াগুলির মধ্যে ডেটা প্রবাহকে পাইপ দেওয়ার সময় শাঁসগুলি আপনাকে যে traditionতিহ্যগত সুবিধা দেয় তা অনুসরণ করে: আপনি প্রতিটি পাইপলাইন পর্যায় একটি স্বতন্ত্র প্রক্রিয়া (সাধারণভাবে, একটি বাফার নিকাশী হতে পারে এবং সাধারণভাবে শেষটি পুরো পাইপলাইনটি তার ধীর প্রক্রিয়া হিসাবে ধীরে চলে। এটি একটি পাইপলাইন প্রক্রিয়া থাকা থেকে পৃথক যা একাধিক থ্রেড ছড়িয়ে দেওয়ার জন্য নিজেই সিদ্ধান্ত নেয় যা পুরোপুরি প্রক্রিয়াটির বাস্তবায়ন বিবরণের উপর নির্ভরশীল।
জোহান বুলি

8

আপনি পরিবর্তনশীল ছাড়াই এটি করতে পারেন can

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

এটি আমাকে একটি "ফরইচ-অবজেক্ট: প্যারামিটার 'প্রক্রিয়া বাঁধতে পারে না।" সিস্টেম.স্ট্রিং "টাইপের" getEnumerator "মানটিকে" System.Management.A 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 = 3এখানে q, a, z হিসাবে "অর্ডার" করা হয়েছে।
ব্যবহারকারী 2864740


0

আপনি যদি পাওয়ারশেল ভি 3 ব্যবহার করে থাকেন তবে আপনি হ্যাশটেবলের পরিবর্তে জেএসএন ব্যবহার করতে পারেন এবং এটিকে কনভার্ট-ফ্রিজ জসনের সাহায্যে কোনও বস্তুতে রূপান্তর করতে পারেন :

@'
[
    {
        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
    }

এনবি কমান্ডটি কনভার্টফ্রম-জসন (এবং কনভার্স, কনভার্ট টো-জসন) - কেবল ড্যাশ প্লেসমেন্টটি অদলবদল করে।
atmarx
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.