C # bir sözlük üzerinde yineleme için birkaç farklı yol gördüm. Standart bir yol var mı?
C # bir sözlük üzerinde yineleme için birkaç farklı yol gördüm. Standart bir yol var mı?
Yanıtlar:
foreach(KeyValuePair<string, string> entry in myDictionary)
{
// do something with entry.Value or entry.Key
}
var entry
Bu durumda kullanmak daha iyidir ve bu yüzden bu cevabı yukarıdaki yerine ikinci bir bakışta oyladım.
var
türü bilmiyorsanız genellikle kötü bir uygulamadır.
var
yalnızca tür derleme zamanında biliniyorsa çalışır. Visual Studio türü biliyorsa, o zaman sizin de öğrenebilirsiniz.
C # 'da genel bir Sözlük kullanmaya çalışıyorsanız, başka bir dilde ilişkilendirilebilir bir dizi kullanırsınız:
foreach(var item in myDictionary)
{
foo(item.Key);
bar(item.Value);
}
Veya yalnızca anahtar toplama işlemi üzerinde yineleme yapmanız gerekiyorsa,
foreach(var item in myDictionary.Keys)
{
foo(item);
}
Son olarak, yalnızca değerlerle ilgileniyorsanız:
foreach(var item in myDictionary.Values)
{
foo(item);
}
( var
Anahtar kelimenin isteğe bağlı C # 3.0 ve üstü bir özellik olduğunu unutmayın, burada anahtarlarınızın / değerlerinizin tam türünü de kullanabilirsiniz)
myDictionary
(tabii ki gerçek isim değilse). Ben tür örneğin açık olduğunda var kullanmanın iyi olduğunu düşünüyorum var x = "some string"
ama hemen belli olmadığı zaman ben kod okuyucu / gözden geçiren acı tembel kodlama düşünüyorum
var
bence, idareli kullanılmalıdır. Özellikle burada, yapıcı değildir: tür KeyValuePair
muhtemelen soru ile ilgilidir.
var
benzersiz bir amacı var ve 'sözdizimsel' şeker olduğuna inanmıyorum. Bunu kasten kullanmak uygun bir yaklaşımdır.
Bazı durumlarda, for-loop uygulaması tarafından sağlanabilecek bir sayaca ihtiyacınız olabilir. Bunun için LINQ ElementAt
aşağıdakileri sağlar:
for (int index = 0; index < dictionary.Count; index++) {
var item = dictionary.ElementAt(index);
var itemKey = item.Key;
var itemValue = item.Value;
}
ElementAt
bir O (n) işlemi?
.ElementAt
bu bağlamda kullanmak küçük hatalara yol açabilir. Arturo'nun yukarıdaki noktası çok daha ciddi. Yalnızca dictionary.Count + 1
O (n) olması gereken bir işlem için O (n ^ 2) karmaşıklığına yol açan sözlük sürelerini yineleyeceksiniz . Gerçekten bir dizine ihtiyacınız varsa (eğer öyleyse, muhtemelen ilk etapta yanlış toplama türünü kullanıyorsunuz), dictionary.Select( (kvp, idx) => new {Index = idx, kvp.Key, kvp.Value})
bunun yerine yinelemelisiniz ve .ElementAt
döngü içinde kullanmamalısınız .
Anahtarların veya değerlerin peşinde olup olmadığınıza bağlıdır ...
MSDN'den Dictionary(TKey, TValue)
Class açıklamasından:
// When you use foreach to enumerate dictionary elements,
// the elements are retrieved as KeyValuePair objects.
Console.WriteLine();
foreach( KeyValuePair<string, string> kvp in openWith )
{
Console.WriteLine("Key = {0}, Value = {1}",
kvp.Key, kvp.Value);
}
// To get the values alone, use the Values property.
Dictionary<string, string>.ValueCollection valueColl =
openWith.Values;
// The elements of the ValueCollection are strongly typed
// with the type that was specified for dictionary values.
Console.WriteLine();
foreach( string s in valueColl )
{
Console.WriteLine("Value = {0}", s);
}
// To get the keys alone, use the Keys property.
Dictionary<string, string>.KeyCollection keyColl =
openWith.Keys;
// The elements of the KeyCollection are strongly typed
// with the type that was specified for dictionary keys.
Console.WriteLine();
foreach( string s in keyColl )
{
Console.WriteLine("Key = {0}", s);
}
Genel olarak, belirli bir bağlam olmadan "en iyi yol" istemek , en iyi rengin ne olduğunu sormak gibidir. ?
Bir yandan, birçok renk var ve en iyi renk yok. İhtiyaca ve çoğu zaman da tada bağlıdır.
Öte yandan, bir Sözlük üzerinde C # yineleme birçok yolu vardır ve en iyi yolu yoktur. İhtiyaca ve çoğu zaman da tada bağlıdır.
foreach (var kvp in items)
{
// key is kvp.Key
doStuff(kvp.Value)
}
Sadece değere ihtiyacınız varsa (buna izin verir item
, daha okunabilir kvp.Value
).
foreach (var item in items.Values)
{
doStuff(item)
}
Genel olarak, yeni başlayanlar bir Sözlüğün numaralandırma sırası konusunda şaşırırlar.
LINQ, siparişi (ve diğer birçok şeyi) belirtmenize izin veren özlü bir sözdizimi sağlar;
foreach (var kvp in items.OrderBy(kvp => kvp.Key))
{
// key is kvp.Key
doStuff(kvp.Value)
}
Yine sadece değere ihtiyacınız olabilir. LINQ ayrıca aşağıdakilere kısa bir çözüm sunar:
item
, daha okunabilir kvp.Value
)İşte burada:
foreach (var item in items.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value))
{
doStuff(item)
}
Bu örneklerden yapabileceğiniz daha birçok gerçek dünya kullanım durumu vardır. Belirli bir siparişe ihtiyacınız yoksa, "en basit yol" a sadık kalın (yukarıya bakın)!
.Values
bir seçme cümlesi değil, olmalıdır .
Value
alanı yok . Burada gördüğüm kesin tip IOrderedEnumerable<KeyValuePair<TKey, TValue>>
. Belki başka bir şey mi demek istediniz? Ne demek istediğinizi gösteren tam bir satır yazabilir misiniz (ve test edin)?
items.Value
önerdiğin gibi yazdım . Yorum yaptığınız dördüncü bölüm söz konusu Select()
olduğunda foreach
, anahtar / değer çiftleri yerine doğrudan sözlükteki değerleri numaralandırmanın bir yoludur . Select()
Bu durumda bir şekilde hoşlanmıyorsanız , üçüncü kod bölümünü tercih edebilirsiniz. Dördüncü bölümün amacı, koleksiyonun LINQ ile önceden işlenebileceğini göstermektir.
.Keys.Orderby()
bir anahtar listesi üzerinde yineleyeceksiniz. İhtiyacın olan tek şey buysa, tamam. Değerlere ihtiyacınız varsa, döngüde değeri elde etmek için her bir anahtardaki sözlüğü sorgulamanız gerekir. Birçok senaryoda pratik bir fark yaratmaz. Yüksek performanslı senaryoda olacak. Cevabın başında yazdığım gibi: "pek çok yol var (...) ve en iyi yol yok. İhtiyaca ve çoğu zaman da tada bağlı."
Açıkçası aradığınız şeye bağlı olsa da, foreach standart bir yol olduğunu söyleyebilirim
foreach(var kvp in my_dictionary) {
...
}
Aradığın şey bu mu?
kvp
yaygın KeyValuePair örneklerini tarif etmek için kullanılmaktadır ilerlerken sözlük ve ilgili veri yapıları üzerinde: foreach(var kvp in myDictionary){...
.
C # 7.0 Deconstructors tanıttı ve .NET Core 2.0+ uygulamakullanıyorsanız, yapıKeyValuePair<>
zatenDeconstruct()
sizin içinbir içerir. Böylece şunları yapabilirsiniz:
var dic = new Dictionary<int, string>() { { 1, "One" }, { 2, "Two" }, { 3, "Three" } };
foreach (var (key, value) in dic) {
Console.WriteLine($"Item [{key}] = {value}");
}
//Or
foreach (var (_, value) in dic) {
Console.WriteLine($"Item [NO_ID] = {value}");
}
//Or
foreach ((int key, string value) in dic) {
Console.WriteLine($"Item [{key}] = {value}");
}
foreach (var (key, value) in dic.Select(x => (x.Key, x.Value)))
Bu sorunun zaten çok fazla cevabı olduğunu takdir ediyorum ama biraz araştırma yapmak istedim.
Bir sözlük üzerinden yineleme, dizi gibi bir şey üzerinde yineleme ile karşılaştırıldığında oldukça yavaş olabilir. Testlerimde, bir dizi üzerindeki bir yineleme 0.015003 saniye sürerken, bir sözlük üzerindeki bir yineleme (aynı sayıda elemanla), 2.4365073 saniye sürdü, bu da 2.4 kat daha uzun! Çok daha büyük farklar görmeme rağmen. Karşılaştırma için bir Liste 0.00215043 saniyede bir yerdeydi.
Ancak, bu elma ve portakalları karşılaştırmak gibidir. Demek istediğim, sözlükler üzerinde yineleme yapmak yavaş.
Sözlükler aramalar için optimize edilmiştir, bu nedenle iki yöntem geliştirdim. Biri sadece bir foreach yapar, diğeri anahtarları tekrarlar ve sonra bakar.
public static string Normal(Dictionary<string, string> dictionary)
{
string value;
int count = 0;
foreach (var kvp in dictionary)
{
value = kvp.Value;
count++;
}
return "Normal";
}
Bu bir anahtarları yükler ve bunun yerine yineliyor (Ben de bir [[] anahtarları çekmeye çalıştım ama fark ihmal edilebilir.
public static string Keys(Dictionary<string, string> dictionary)
{
string value;
int count = 0;
foreach (var key in dictionary.Keys)
{
value = dictionary[key];
count++;
}
return "Keys";
}
Bu örnekle normal foreach testi 0.0310062 ve anahtar versiyonu 0.2205441 aldı. Tüm anahtarları yüklemek ve tüm aramalar üzerinde yineleme yapmak çok daha yavaştır!
Son bir test için, burada anahtarları kullanmanın herhangi bir faydası olup olmadığını görmek için on kez yinelememi gerçekleştirdim (bu noktaya kadar sadece merak ettim):
Olanları görselleştirmenize yardımcı oluyorsa RunTest yöntemi şöyledir.
private static string RunTest<T>(T dictionary, Func<T, string> function)
{
DateTime start = DateTime.Now;
string name = null;
for (int i = 0; i < 10; i++)
{
name = function(dictionary);
}
DateTime end = DateTime.Now;
var duration = end.Subtract(start);
return string.Format("{0} took {1} seconds", name, duration.TotalSeconds);
}
Burada normal foreach koşusu 0.2820564 saniye sürdü (beklediğiniz gibi tek bir yinelemeden yaklaşık on kat daha uzun). Anahtarların yinelenmesi 2.2249449 saniye sürdü.
Eklemek İçin Düzenlendi: Diğer cevapların bazılarını okumak, Sözlük yerine Sözlük kullanırsam ne olacağını sorgulamamı sağladı. Bu örnekte dizi 0.0120024 saniye, liste 0.0185037 saniye ve sözlük 0.0465093 saniye sürdü. Veri türünün, sözlüğün ne kadar yavaş olduğu konusunda bir fark yaratmasını beklemek mantıklıdır.
Sonuçlarım nelerdir?
Birçok seçenek var. Kişisel favorim KeyValuePair tarafından
Dictionary<string, object> myDictionary = new Dictionary<string, object>();
// Populate your dictionary here
foreach (KeyValuePair<string,object> kvp in myDictionary)
{
// Do some interesting things
}
Anahtarlar ve Değerler Koleksiyonlarını da kullanabilirsiniz
.NET Framework 4.7
Biri ile ayrışma kullanabilirsiniz
var fruits = new Dictionary<string, int>();
...
foreach (var (fruit, number) in fruits)
{
Console.WriteLine(fruit + ": " + number);
}
Bu kodun daha düşük C # sürümlerinde çalışmasını sağlamak için bir System.ValueTuple NuGet package
yere ekleyin ve yazın
public static class MyExtensions
{
public static void Deconstruct<T1, T2>(this KeyValuePair<T1, T2> tuple,
out T1 key, out T2 value)
{
key = tuple.Key;
value = tuple.Value;
}
}
ValueTuple
yerleşiktir. Önceki sürümler için bir nuget paketi olarak kullanılabilir. Daha da önemlisi, Deconstruct
yöntemin bir yapısökücü olarak çalışması için C # 7.0+ gereklidir var (fruit, number) in fruits
.
C # 7'den itibaren, nesneleri değişkenler halinde yapılandırabilirsiniz. Bunun bir sözlük üzerinden yinelemenin en iyi yolu olduğuna inanıyorum.
Misal:
KeyValuePair<TKey, TVal>
Bu yapıyı bozan bir uzantı yöntemi oluşturun :
public static void Deconstruct<TKey, TVal>(this KeyValuePair<TKey, TVal> pair, out TKey key, out TVal value)
{
key = pair.Key;
value = pair.Value;
}
Dictionary<TKey, TVal>
Aşağıdaki şekilde yineleyin
// Dictionary can be of any types, just using 'int' and 'string' as examples.
Dictionary<int, string> dict = new Dictionary<int, string>();
// Deconstructor gets called here.
foreach (var (key, value) in dict)
{
Console.WriteLine($"{key} : {value}");
}
Tekrarlamak için aşağıda önerdin
Dictionary<string,object> myDictionary = new Dictionary<string,object>();
//Populate your dictionary here
foreach (KeyValuePair<string,object> kvp in myDictionary) {
//Do some interesting things;
}
FYI, foreach
değer type nesnesiyse çalışmaz.
foreach
çalışmaz ? Aksi takdirde bu pek mantıklı değil. object
C # 7 kullanarak , bu uzantı yöntemini çözümünüzün herhangi bir projesine ekleyin:
public static class IDictionaryExtensions
{
public static IEnumerable<(TKey, TValue)> Tuples<TKey, TValue>(
this IDictionary<TKey, TValue> dict)
{
foreach (KeyValuePair<TKey, TValue> kvp in dict)
yield return (kvp.Key, kvp.Value);
}
}
Ve bu basit sözdizimini kullanın
foreach (var(id, value) in dict.Tuples())
{
// your code using 'id' and 'value'
}
Veya bu, eğer isterseniz
foreach ((string id, object value) in dict.Tuples())
{
// your code using 'id' and 'value'
}
Geleneksel yerine
foreach (KeyValuePair<string, object> kvp in dict)
{
string id = kvp.Key;
object value = kvp.Value;
// your code using 'id' and 'value'
}
Uzatma yöntemi dönüştüren KeyValuePair
, aramalarınızdan IDictionary<TKey, TValue>
kesinlikle yazılı içine tuple
bu yeni konforlu sözdizimini kullanmak için izin.
-Just- gerekli sözlük girişlerini tuples
dönüştürür tuples
, bu yüzden tüm sözlüğü dönüştürmez , dolayısıyla bununla ilgili performans kaygısı yoktur.
Doğrudan tuple
kullanarak karşılaştırmak için bir genişletme yöntemi çağıran sadece küçük bir maliyet KeyValuePair
vardır, KeyValuePair
's özellikleri Key
ve Value
yine de yeni döngü değişkenleri atarsanız bir sorun OLMAMALIDIR .
Pratikte, bu yeni sözdizimi, hala belirli bir noktada kullanmama seçeneğiniz olan düşük seviyeli ultra yüksek performans senaryoları dışında çoğu durum için çok uygundur.
Şuna göz atın: MSDN Blog - C # 7'deki yeni özellikler
kvp.Key
ve kvp.Value
sırasıyla anahtar ve değer kullanılmalıdır. Tuples ile, foreach bloğunun içinde başka değişken bildirimleri kullanmadan anahtarı ve değeri istediğiniz gibi adlandırma esnekliği elde edersiniz. Örneğin, anahtarınızı şu şekilde adlandırabilirsiniz: factoryName
ve değeri models
, özellikle iç içe döngüler (sözlüklerin sözlükleri) aldığınızda yararlıdır: kod bakımı çok daha kolay hale gelir. Sadece bir deneyin! ;-)
Bunun çok eski bir soru olduğunu biliyorum, ancak yararlı olabilecek bazı uzantı yöntemleri oluşturdum:
public static void ForEach<T, U>(this Dictionary<T, U> d, Action<KeyValuePair<T, U>> a)
{
foreach (KeyValuePair<T, U> p in d) { a(p); }
}
public static void ForEach<T, U>(this Dictionary<T, U>.KeyCollection k, Action<T> a)
{
foreach (T t in k) { a(t); }
}
public static void ForEach<T, U>(this Dictionary<T, U>.ValueCollection v, Action<U> a)
{
foreach (U u in v) { a(u); }
}
Bu şekilde böyle bir kod yazabilirsiniz:
myDictionary.ForEach(pair => Console.Write($"key: {pair.Key}, value: {pair.Value}"));
myDictionary.Keys.ForEach(key => Console.Write(key););
myDictionary.Values.ForEach(value => Console.Write(value););
Bazen yalnızca numaralandırılması gereken değerlere ihtiyacınız varsa, sözlüğün değer toplamasını kullanın:
foreach(var value in dictionary.Values)
{
// do something with entry.Value only
}
En hızlı yöntem olduğunu belirten bu yazı tarafından bildirildi: http://alexpinsker.blogspot.hk/2010/02/c-fastest-way-to-iterate-over.html
Bu yöntemi MSDN'de DictionaryBase sınıfının belgelerinde buldum:
foreach (DictionaryEntry de in myDictionary)
{
//Do some stuff with de.Value or de.Key
}
DictionaryBase'den devralınan bir sınıfta düzgün çalışabildiğim tek kişi buydu.
Hashtable
nesneler için kullanılan jenerik olmayan bir sürümdür
ContainsKey()
içinde for
sürümüne? Bu, karşılaştırdığınız kodda bulunmayan fazladan ek yük getirir. TryGetValue()
"anahtar varsa, öğeyi anahtarla al" deseninin yerini almak için vardır. Bundan başka, eğer dict
gelen tamsayılar bitişik bir dizi içerir 0
için dictCount - 1
, dizinleyici başarısız olamaz biliyorum; aksi halde dict.Keys
yinelemeniz gereken şey budur. Her iki şekilde de, hayır ContainsKey()
/ TryGetValue()
gerekli. Son olarak, lütfen kodun ekran görüntülerini göndermeyin.
Bir sözlük üzerinde döngü için bir uzantı yazdım.
public static class DictionaryExtension
{
public static void ForEach<T1, T2>(this Dictionary<T1, T2> dictionary, Action<T1, T2> action) {
foreach(KeyValuePair<T1, T2> keyValue in dictionary) {
action(keyValue.Key, keyValue.Value);
}
}
}
Sonra arayabilirsin
myDictionary.ForEach((x,y) => Console.WriteLine(x + " - " + y));
ForEach
yöntemi tanımladınız foreach (...) { }
... Gereksiz gibi görünüyor.
Eğer diyelim, varsayılan olarak değerler koleksiyonu üzerinde yineleme yapmak istiyorsanız, IEnumerable <> uygulayabileceğinize inanıyorum, burada T sözlükteki değerler nesnesinin türüdür ve "this" bir Sözlüktür.
public new IEnumerator<T> GetEnumerator()
{
return this.Values.GetEnumerator();
}
Sadece en çok cevap foreach-loop ile ilgili olarak, benim 2 cent eklemek istedim. Lütfen aşağıdaki koda bir göz atın:
Dictionary<String, Double> myProductPrices = new Dictionary<String, Double>();
//Add some entries to the dictionary
myProductPrices.ToList().ForEach(kvP =>
{
kvP.Value *= 1.15;
Console.Writeline(String.Format("Product '{0}' has a new price: {1} $", kvp.Key, kvP.Value));
});
Bu '.ToList ()' bir ek çağrıyı ekler altought (belirttiği gibi burada hafif bir performans iyileştirme olabilir someList.Foreach () {} vs foreach , büyük Sözlükler ile çalışan ve paralel çalışan espacially zaman hayır) seçeneğinin hiç etkisi olmaz.
Ayrıca, foreach döngüsü içindeki 'Değer' özelliğine değer atayamayacağınızı lütfen unutmayın. Öte yandan, 'Anahtar'ı da manipüle edebileceksiniz, muhtemelen çalışma zamanında başınızı belaya sokacaksınız.
Anahtarları ve Değerleri sadece "okumak" istediğinizde, IEnumerable.Select () öğesini de kullanabilirsiniz.
var newProductPrices = myProductPrices.Select(kvp => new { Name = kvp.Key, Price = kvp.Value * 1.15 } );
foreach
yan etki görünürlüğünü ait olduğu yere kadar zorlar.
var dictionary = new Dictionary<string, int>
{
{ "Key", 12 }
};
var aggregateObjectCollection = dictionary.Select(
entry => new AggregateObject(entry.Key, entry.Value));
AggregateObject
ekler KeyValuePair
? Soruda istendiği gibi "yineleme" nerede?
foreach
, ama çok kullandım. Cevabım gerçekten inmeyi hak etti mi?
Select
kullanır , ancak yineleyicinin kendisi değildir. Yineleme ( foreach
) için kullanılan şey türleri - özellikle yan etkileri olan işlemler - Linq'in kapsamı dışındadır Select
. Lambda aggregateObjectCollection
aslında numaralandırılana kadar koşmayacak . Eğer bu cevap bir "ilk yol" olarak alınırsa (yani bir düzlükten önce kullanılırsa foreach
) kötü uygulamaları teşvik eder. Durumsal olarak, bir sözlüğü tekrarlamadan önce yardımcı olan , ancak soruyu sorulduğu gibi ele almayan Linq işlemleri olabilir .
Sözlük <TKey, TValue> Bu c # genel bir toplama sınıfıdır ve verileri anahtar / değer biçiminde saklar.Anahtar benzersiz olmalı ve değer olmamalı, değer yinelenebilir ve null olabilir. Sözlükteki her öğe olduğu gibi bir anahtarı ve değerini temsil eden KeyValuePair <TKey, TValue> yapısı olarak kabul edilir. ve dolayısıyla elemanın yinelemesi sırasında KeyValuePair <TKey, TValue> eleman tipini almalıyız. Aşağıda örnek.
Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1,"One");
dict.Add(2,"Two");
dict.Add(3,"Three");
foreach (KeyValuePair<int, string> item in dict)
{
Console.WriteLine("Key: {0}, Value: {1}", item.Key, item.Value);
}
Döngü için kullanmak istiyorsanız, bunu yapabilirsiniz:
var keyList=new List<string>(dictionary.Keys);
for (int i = 0; i < keyList.Count; i++)
{
var key= keyList[i];
var value = dictionary[key];
}
foreach
döngü ve çünkü kötü bir performans new List<string>(dictionary.Keys)
yineleme olacak dictionary.Count
hatta kendin yineleme şansı önce kez. "En iyi yolu" istemenin öznel olduğunu bir kenara bırakarak, sorunun nasıl "en iyi yol" veya "standart yol" olarak nitelendirileceğini görmüyorum. "Eğer döngü için kullanmak istiyorsanız ..." Kime ı ile karşı koyacaktır " Do not bir kullanmak for
döngü."
foreach (var pair in dictionary.ToArray()) { }
. Yine de, cevapta birinin bu kodu kullanmak isteyeceği belirli senaryo (ları) ve bunu yapmanın sonuçlarını açıklığa kavuşturmanın iyi olacağını düşünüyorum.
linq ile basit
Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1, "American Ipa");
dict.Add(2, "Weiss");
dict.ToList().ForEach(x => Console.WriteLine($"key: {x.Key} | value: {x.Value}") );
ToList()
çünkü ForEach()
sadece List<>
sınıfta tanımlanmışsınız , ama neden sadece bunun yerine bunu yapıyorsunuz foreach (var pair in dict) { }
? Bunun daha da basit olduğunu ve aynı bellek / performans sonuçları olmadığını söyleyebilirim. Bu kesin çözüm zaten 3.5 yıl önceki bu cevapta önerilmişti .
kullanma arasında bir tartışma olduğu en yüksek dereceli gönderilere ek olarak
foreach(KeyValuePair<string, string> entry in myDictionary)
{
// do something with entry.Value or entry.Key
}
veya
foreach(var entry in myDictionary)
{
// do something with entry.Value or entry.Key
}
başlatma işleminden sözlük türünü görebildiğiniz için en eksiksiz olan aşağıdaki, kvp KeyValuePair
var myDictionary = new Dictionary<string, string>(x);//fill dictionary with x
foreach(var kvp in myDictionary)//iterate over dictionary
{
// do something with kvp.Value or kvp.Key
}