Enumerable.Zip
Linq में विस्तार विधि का उपयोग क्या है ?
Enumerable.Zip
Linq में विस्तार विधि का उपयोग क्या है ?
जवाबों:
ज़िप ऑपरेटर एक निर्दिष्ट चयनकर्ता फ़ंक्शन का उपयोग करके दो अनुक्रमों के संबंधित तत्वों को मिलाता है।
var letters= new string[] { "A", "B", "C", "D", "E" };
var numbers= new int[] { 1, 2, 3 };
var q = letters.Zip(numbers, (l, n) => l + n.ToString());
foreach (var s in q)
Console.WriteLine(s);
ouput
A1
B2
C3
Zip
विकल्प लिखें । बी) के लिए एक विधि लिखें yield return
छोटी सूची के प्रत्येक तत्व, और उसके बाद जारी रखने के yield return
ing default
अनिश्चित काल के लिए उसके बाद। (विकल्प बी के लिए आपको पहले से जानना आवश्यक है कि कौन सी सूची छोटी है।)
Zip
एक में दो दृश्यों के संयोजन के लिए है। उदाहरण के लिए, यदि आपके पास सीक्वेंस हैं
1, 2, 3
तथा
10, 20, 30
और आप वह क्रम चाहते हैं जो प्राप्त करने के लिए प्रत्येक अनुक्रम में एक ही स्थिति में तत्वों को गुणा करने का परिणाम है
10, 40, 90
तुम कह सकते हो
var left = new[] { 1, 2, 3 };
var right = new[] { 10, 20, 30 };
var products = left.Zip(right, (m, n) => m * n);
इसे "ज़िप" कहा जाता है क्योंकि आप एक अनुक्रम को एक ज़िप के बाईं ओर के रूप में सोचते हैं, और दूसरा क्रम ज़िप के दाईं ओर के रूप में है, और ज़िप ऑपरेटर दोनों पक्षों को एक साथ खींचकर दांत निकाल देगा ( अनुक्रम के तत्व) उचित रूप से।
यह दो अनुक्रमों के माध्यम से पुनरावृत्त करता है और उनके तत्वों को एक-एक करके, एक नए अनुक्रम में जोड़ता है। तो आप अनुक्रम ए का एक तत्व लेते हैं, इसे अनुक्रम बी से संबंधित तत्व के साथ बदलते हैं, और परिणाम अनुक्रम सी का एक तत्व बनाता है।
इसके बारे में सोचने का एक तरीका यह है कि यह Select
एक संग्रह से आइटम बदलने के बजाय, एक ही बार में दो संग्रह पर काम करता है।
विधि पर MSDN आलेख से :
int[] numbers = { 1, 2, 3, 4 };
string[] words = { "one", "two", "three" };
var numbersAndWords = numbers.Zip(words, (first, second) => first + " " + second);
foreach (var item in numbersAndWords)
Console.WriteLine(item);
// This code produces the following output:
// 1 one
// 2 two
// 3 three
यदि आप इसे अनिवार्य कोड में करना चाहते हैं, तो आप शायद ऐसा कुछ करेंगे:
for (int i = 0; i < numbers.Length && i < words.Length; i++)
{
numbersAndWords.Add(numbers[i] + " " + words[i]);
}
या यदि LINQ इसमें नहीं था Zip
, तो आप ऐसा कर सकते हैं:
var numbersAndWords = numbers.Select(
(num, i) => num + " " + words[i]
);
यह तब उपयोगी होता है जब आपके पास डेटा समान, सरणी जैसी सूचियों में फैला होता है, प्रत्येक समान लंबाई और क्रम के साथ होता है, और प्रत्येक वस्तुओं के समान सेट की एक अलग संपत्ति का वर्णन करता है। Zip
आपको डेटा के उन टुकड़ों को एक साथ एक सुसंगत संरचना में बुनने में मदद करता है।
इसलिए यदि आपके पास राज्य के नाम का एक सरणी और उनके संक्षिप्त विवरण का एक और सरणी है, तो आप उन्हें इस State
तरह एक वर्ग में मिला सकते हैं:
IEnumerable<State> GetListOfStates(string[] stateNames, int[] statePopulations)
{
return stateNames.Zip(statePopulations,
(name, population) => new State()
{
Name = name,
Population = population
});
}
Select
नाम Zip
को आपको फेंकने न दें । यह एक फ़ाइल या एक फ़ोल्डर ज़िप करने के रूप में zipping के साथ कुछ नहीं करना है (संपीड़ित)। यह वास्तव में इसका नाम मिलता है कि कपड़े पर जिपर कैसे काम करता है: कपड़े पर जिपर के 2 पक्ष होते हैं और प्रत्येक पक्ष में दांतों का एक गुच्छा होता है। जब आप एक दिशा में जाते हैं, तो जिपर दोनों तरफ से घूमता है और दांतों को बंद करके जिपर को बंद कर देता है। जब आप दूसरी दिशा में जाते हैं तो यह दांतों को खोलता है। आप या तो एक खुले या बंद ज़िप के साथ समाप्त होते हैं।
यह Zip
विधि के साथ एक ही विचार है । एक उदाहरण पर विचार करें जहां हमारे पास दो संग्रह हैं। एक अक्षर रखता है और दूसरा एक खाद्य पदार्थ का नाम रखता है जो उस अक्षर से शुरू होता है। स्पष्टता प्रयोजनों के लिए मैं उन्हें बोल रहा हूँ leftSideOfZipper
और rightSideOfZipper
। यहाँ कोड है।
var leftSideOfZipper = new List<string> { "A", "B", "C", "D", "E" };
var rightSideOfZipper = new List<string> { "Apple", "Banana", "Coconut", "Donut" };
हमारा काम एक संग्रह का उत्पादन करना है जिसमें फल का अक्षर ए :
और उसके नाम से अलग होता है । ऐशे ही:
A : Apple
B : Banana
C : Coconut
D : Donut
Zip
बचाव के लिए। अपनी ज़िप शब्दावली के साथ बने रहने के लिए हम इस परिणाम closedZipper
को कहेंगे leftTooth
और बाएं ज़िप के आइटम को हम कॉल करेंगे और दाईं ओर हम righTooth
स्पष्ट कारणों के लिए कॉल करेंगे :
var closedZipper = leftSideOfZipper
.Zip(rightSideOfZipper, (leftTooth, rightTooth) => leftTooth + " : " + rightTooth).ToList();
ऊपर हम जिपर के बाईं ओर और जिपर के दाईं ओर (यात्रा कर रहे हैं) की गणना कर रहे हैं और प्रत्येक दांत पर एक ऑपरेशन कर रहे हैं। हम जो ऑपरेशन कर रहे हैं वह बाएं दाँत (भोजन पत्र) :
और फिर दाँत (भोजन का नाम) के साथ बदल रहा है। हम इस कोड का उपयोग करते हैं:
(leftTooth, rightTooth) => leftTooth + " : " + rightTooth)
अंतिम परिणाम यह है:
A : Apple
B : Banana
C : Coconut
D : Donut
अंतिम अक्षर E का क्या हुआ?
यदि आप एक असली कपड़े की ज़िप और एक तरफ की गणना (खींच) कर रहे हैं, तो बाईं ओर या दाईं ओर कोई फर्क नहीं पड़ता, दूसरे पक्ष की तुलना में कम दांत हैं, क्या होगा? खैर जिपर वहीं रुक जाएगा। Zip
विधि बिल्कुल वैसा ही करना होगा: यह बंद हो जाएगा एक बार यह दोनों तरफ पिछले आइटम तक पहुँच गया है। हमारे मामले में दाईं ओर के दाँत (भोजन के नाम) कम हैं, इसलिए यह "डोनट" पर रुक जाएगा।
मेरे पास टिप्पणी अनुभाग में पोस्ट करने के लिए प्रतिनिधि अंक नहीं हैं, लेकिन संबंधित प्रश्न का उत्तर देने के लिए:
क्या होगा अगर मैं जिप जारी रखना चाहता हूं जहां एक सूची तत्वों से बाहर चलती है? जिस स्थिति में छोटी सूची तत्व को डिफ़ॉल्ट मान लेना चाहिए। इस मामले में आउटपुट A1, B2, C3, D0, E0 होना चाहिए। - लियांग 19 '15 को 3:29 बजे
आप क्या करेंगे Array.Resize का उपयोग करें (डिफ़ॉल्ट मान के साथ छोटे अनुक्रम को पैड-आउट करने के लिए, और फिर उन्हें एक साथ ज़िप करें)।
कोड उदाहरण:
var letters = new string[] { "A", "B", "C", "D", "E" };
var numbers = new int[] { 1, 2, 3 };
if (numbers.Length < letters.Length)
Array.Resize(ref numbers, letters.Length);
var q = letters.Zip(numbers, (l, n) => l + n.ToString());
foreach (var s in q)
Console.WriteLine(s);
आउटपुट:
A1
B2
C3
D0
E0
कृपया ध्यान दें कि Array.Resize () का उपयोग करके एक चेतावनी है : C # में Redim संरक्षित करें?
यदि यह अज्ञात है कि कौन सा अनुक्रम छोटा होगा, तो एक फ़ंक्शन बनाया जा सकता है जो इसे बनाता है:
static void Main(string[] args)
{
var letters = new string[] { "A", "B", "C", "D", "E" };
var numbers = new int[] { 1, 2, 3 };
var q = letters.Zip(numbers, (l, n) => l + n.ToString()).ToArray();
var qDef = ZipDefault(letters, numbers);
Array.Resize(ref q, qDef.Count());
// Note: using a second .Zip() to show the results side-by-side
foreach (var s in q.Zip(qDef, (a, b) => string.Format("{0, 2} {1, 2}", a, b)))
Console.WriteLine(s);
}
static IEnumerable<string> ZipDefault(string[] letters, int[] numbers)
{
switch (letters.Length.CompareTo(numbers.Length))
{
case -1: Array.Resize(ref letters, numbers.Length); break;
case 0: goto default;
case 1: Array.Resize(ref numbers, letters.Length); break;
default: break;
}
return letters.Zip(numbers, (l, n) => l + n.ToString());
}
ZipDefault के साथ सादे .Zip () का आउटपुट:
A1 A1
B2 B2
C3 C3
D0
E0
मूल प्रश्न के मुख्य उत्तर पर जा रहे हैं , एक और दिलचस्प बात जो कोई भी करना चाहता है (जब अनुक्रम की लंबाई "ज़िपित" अलग हो) उन्हें इस तरह से शामिल करना है ताकि सूची का अंत हो शीर्ष के बजाय मैच। यह। स्किप () का उपयोग करके उचित संख्या में "लंघन" द्वारा पूरा किया जा सकता है।
foreach (var s in letters.Skip(letters.Length - numbers.Length).Zip(numbers, (l, n) => l + n.ToString()).ToArray())
Console.WriteLine(s);
आउटपुट:
C1
D2
E3
public static IEnumerable<T> Pad<T>(this IEnumerable<T> input, long minLength, T value = default(T)) { long numYielded = 0; foreach (T element in input) { yield return element; ++numYielded; } while (numYielded < minLength) { yield return value; ++numYielded; } }
यहां बहुत सारे उत्तर प्रदर्शित होते हैं Zip
, लेकिन वास्तव में एक वास्तविक जीवन उपयोग-मामले की व्याख्या किए बिना जो उपयोग के लिए प्रेरित करेगा Zip
।
एक विशेष रूप से सामान्य पैटर्न जो Zip
चीजों के क्रमिक जोड़े पर चलने के लिए शानदार है। यह X
1 तत्व को छोड़ते हुए, अपने साथ एक एन्यूमरेट को पुनरावृत्त करके किया जाता है x.Zip(x.Skip(1)
:। दृश्य उदाहरण:
x | x.Skip(1) | x.Zip(x.Skip(1), ...)
---+-----------+----------------------
| 1 |
1 | 2 | (1, 2)
2 | 3 | (2, 1)
3 | 4 | (3, 2)
4 | 5 | (4, 3)
ये क्रमिक जोड़े मूल्यों के बीच पहले अंतर को खोजने के लिए उपयोगी हैं। उदाहरण के लिए, क्रमिक जोड़े का IEnumable<MouseXPosition>
उत्पादन करने के लिए इस्तेमाल किया जा सकता है IEnumerable<MouseXDelta>
। इसी तरह, कैन के सैंपल bool
वैल्यूज़ को / / / button
जैसी घटनाओं में व्याख्यायित किया जा सकता है । उन घटनाओं के बाद प्रतिनिधि विधियों को कॉल चला सकते हैं। यहाँ एक उदाहरण है:NotPressed
Clicked
Held
Released
using System;
using System.Collections.Generic;
using System.Linq;
enum MouseEvent { NotPressed, Clicked, Held, Released }
public class Program {
public static void Main() {
// Example: Sampling the boolean state of a mouse button
List<bool> mouseStates = new List<bool> { false, false, false, false, true, true, true, false, true, false, false, true };
mouseStates.Zip(mouseStates.Skip(1), (oldMouseState, newMouseState) => {
if (oldMouseState) {
if (newMouseState) return MouseEvent.Held;
else return MouseEvent.Released;
} else {
if (newMouseState) return MouseEvent.Clicked;
else return MouseEvent.NotPressed;
}
})
.ToList()
.ForEach(mouseEvent => Console.WriteLine(mouseEvent) );
}
}
प्रिंटों:
NotPressesd
NotPressesd
NotPressesd
Clicked
Held
Held
Released
Clicked
Released
NotPressesd
Clicked
जैसा कि दूसरों ने कहा है, जिप आपको आगे के लिन्क स्टेटमेंट्स या एक फॉरेक्स लूप में उपयोग के लिए दो संग्रह को संयोजित करने देता है।
लूप और दो सरणियों के लिए जिन ऑपरेशनों की आवश्यकता होती है, वे अब एक अनाम ऑब्जेक्ट का उपयोग करके फ़ॉरच लूप में किए जा सकते हैं।
एक उदाहरण जो मैंने अभी खोजा है, वह मूर्खतापूर्ण है, लेकिन उपयोगी हो सकता है अगर समानांतर लाभकारी होते हैं तो साइड इफेक्ट्स के साथ एक एकल पंक्ति क्यू ट्रैवर्सल होगा:
timeSegments
.Zip(timeSegments.Skip(1), (Current, Next) => new {Current, Next})
.Where(zip => zip.Current.EndTime > zip.Next.StartTime)
.AsParallel()
.ForAll(zip => zip.Current.EndTime = zip.Next.StartTime);
timeSegments एक कतार में वर्तमान या हटाए गए आइटम का प्रतिनिधित्व करता है (अंतिम तत्व ज़िप द्वारा काट दिया जाता है)। timeSegments.Skip (1) एक कतार में अगले या तिरछी वस्तुओं का प्रतिनिधित्व करता है। ज़िप विधि इन दोनों को एक अगली और वर्तमान संपत्ति के साथ एक एकल अनाम वस्तु में जोड़ती है। फिर हम कहां से फ़िल्टर करते हैं और AsParallel () के साथ परिवर्तन करते हैं। बेशक अंतिम बिट नियमित रूप से फोरचेक हो सकता है या एक और चुनिंदा बयान हो सकता है जो आपत्तिजनक समय खंडों को लौटाता है।
ज़िप विधि आपको दो असंबंधित अनुक्रमों को "मर्ज" करने की अनुमति देता है, आपके द्वारा एक विलय फ़ंक्शन प्रदाता का उपयोग करके, कॉलर। MSDN पर उदाहरण वास्तव में यह दर्शाता है कि आप ज़िप के साथ क्या कर सकते हैं। इस उदाहरण में, आप दो मनमाना, असंबंधित अनुक्रम लेते हैं, और उन्हें एक मनमाना फ़ंक्शन का उपयोग करके संयोजित करते हैं (इस मामले में, दोनों अनुक्रमों से केवल एक स्ट्रिंग में आइटम समेटते हैं)।
int[] numbers = { 1, 2, 3, 4 };
string[] words = { "one", "two", "three" };
var numbersAndWords = numbers.Zip(words, (first, second) => first + " " + second);
foreach (var item in numbersAndWords)
Console.WriteLine(item);
// This code produces the following output:
// 1 one
// 2 two
// 3 three
string[] fname = { "mark", "john", "joseph" };
string[] lname = { "castro", "cruz", "lopez" };
var fullName = fname.Zip(lname, (f, l) => f + " " + l);
foreach (var item in fullName)
{
Console.WriteLine(item);
}
// The output are
//mark castro..etc