我的数据结构如下。
Dictionary<Blopp, List<double>> data = ...;
人们可以看到,它确实是一种字典列表。而现在,我需要独立访问它们。所以我希望得到这样的东西。
for(int i = 0; i < data.First().Value.Count; i++)
{
Dictionary<Blopp, double> partial = ...;
// do stuff to the partial number i
}
我该怎么做?
我用谷歌搜索但是有点难以用goolenglish来解释我正在寻找什么,所以我得到了杰克。 :(
修改
显然,不仅谷歌搜索令人困惑,因此,正如所建议的那样,我提供了一个基于数据的例子。
之前的状态:
{A:{q,w,e,r},B:{a,s,d,f},C:{z,x,c,v}}
状态请求外循环的第一次迭代。
{A:q,B:a,C:z}
状态请求外循环的第二次迭代。
{A:w,B:s,C:x}
State请求外循环的第三次迭代。
{A:e,B:d,C:c}
在上面的伪示例中,大写代表键,而小写代表双键。
答案 0 :(得分:1)
你可以这样做:
var firstEntry = data.First();
for(int i = 0; i < firstEntry.Value.Count; i++)
{
Dictionary<Blopp, double> partial = data.ToDictionary(x => x.Key, x => x.Value[i]);
// do stuff to the partial number i
}
或者您可以使用LINQ将整个数据转换为单独的词典列表:
List<Dictionary<Blopp,double>> listOfDict =
Enumerable.Range(0,data.First().Value.Count)
.Select(i => data.ToDictionary(x => x.Key, x => x.Value[i]))
.ToList();
编辑:
之前的两种方法都会创建大量的一次性字典。如果您不需要修改它们并且只需要执行查找,那么这当然效率低下且无用。所以,我会寻找一种利用一些包装类的扩展方法:
static class MultiDictionaryExtension
{
#region Extension
public static IEnumerable<IDictionary<TK, TV>> AsSeparatedDictionaries<TK, TV>(this IDictionary<TK, List<TV>> multiDict)
{
int numDictionaries = multiDict.First().Value.Count;
for (int i = 0; i < numDictionaries; i++)
yield return new SingleDictionaryWrap<TK, TV>(multiDict, i);
}
#endregion
#region Helper classes
public class SingleDictionaryWrap<TK, TV> : IDictionary<TK, TV>
{
private class ValueCollection : ICollection<TV>
{
private readonly SingleDictionaryWrap<TK, TV> dict;
public ValueCollection(SingleDictionaryWrap<TK, TV> dict)
{
this.dict = dict;
}
public int Count { get { return this.dict.Count; } }
public bool IsReadOnly { get { return false; } }
public void Add(TV item) { throw new NotSupportedException("This dictionary is readonly"); }
public void Clear() { throw new NotSupportedException("This dictionary is readonly"); }
public bool Contains(TV item) { return this.dict.Select(x => x.Value).Contains(item); }
public void CopyTo(TV[] array, int arrayIndex) { foreach (var item in this) array[arrayIndex++] = item; }
public IEnumerator<TV> GetEnumerator() { return this.dict.Select(x => x.Value).GetEnumerator(); }
public bool Remove(TV item) { throw new NotSupportedException("This dictionary is readonly"); }
IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); }
}
private readonly IDictionary<TK, List<TV>> multiDict;
public int Index { get; private set; }
public SingleDictionaryWrap(IDictionary<TK, List<TV>> multiDict, int index)
{
this.Index = index;
this.multiDict = multiDict;
}
public ICollection<TK> Keys { get { return this.multiDict.Keys; } }
public ICollection<TV> Values { get { return new ValueCollection(this); } }
public int Count { get { return this.multiDict.Count; } }
public bool IsReadOnly { get { return true; } }
public TV this[TK key]
{
get { return this.multiDict[key][this.Index]; }
set { throw new NotSupportedException("This dictionary is readonly"); }
}
public bool ContainsKey(TK key) { return this.multiDict.ContainsKey(key); }
public void Add(TK key, TV value) { throw new NotSupportedException("This dictionary is readonly"); }
public bool Remove(TK key) { throw new NotSupportedException("This dictionary is readonly"); }
public bool TryGetValue(TK key, out TV value)
{
value = default(TV);
List<TV> values;
if (this.multiDict.TryGetValue(key, out values))
{
value = values[this.Index];
return true;
}
return false;
}
public void Add(KeyValuePair<TK, TV> item) { throw new NotSupportedException("This dictionary is readonly"); }
public void Clear() { throw new NotSupportedException("This dictionary is readonly"); }
public bool Contains(KeyValuePair<TK, TV> item)
{
TV value;
if (this.TryGetValue(item.Key, out value))
{
return Object.Equals(value, item.Value);
}
return false;
}
public void CopyTo(KeyValuePair<TK, TV>[] array, int arrayIndex) { foreach (var kvp in this) array[arrayIndex++] = kvp; }
public bool Remove(KeyValuePair<TK, TV> item) { throw new NotSupportedException("This dictionary is readonly"); }
public IEnumerator<KeyValuePair<TK, TV>> GetEnumerator() { return this.multiDict.Select(kvp => new KeyValuePair<TK, TV>(kvp.Key, kvp.Value[this.Index])).GetEnumerator(); }
IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); }
}
#endregion
}
相当长的扩展类,但看看它如何使一切变得更简单:
foreach (var partial in dict.AsSeparatedDictionaries())
{
// use partial as a normal IDictionary<Blopp,double>
// if you need the current "i" use partial.Index
}
免责声明:
所有以前的代码都假设所有内部列表具有完全相同的长度。
答案 1 :(得分:0)
我相信这会做你想要的。可能有一种更简单的方法可以做到这一点,如果我想到它我会更新答案,即使内部列表的长度不同,这段代码也能正常工作。
static void Main(string[] args)
{
Dictionary<Blopp, List<double>> data = CreateData();
List<Dictionary<Blopp, double>> result = PiviotDictionary(data).ToList();
}
private static IEnumerable<Dictionary<TKey, TValue>> GetSingleEntires<TKey,TValue>(Dictionary<TKey, List<TValue>> data)
{
bool foundValue = true;
for(int i = 0; foundValue == true; i++)
{
foundValue = false;
var result = new Dictionary<TKey, TValue>();
foreach (var kvp in data)
{
if (kvp.Value.Count > i)
{
foundValue = true;
result.Add(kvp.Key, kvp.Value[i]);
}
}
if (foundValue)
yield return result;
}
}