我有两个或更多数组 - 一个有ID,一个或多个有字符串值。我想将它们合并到一个哈希表中,这样我就可以按ID查找值。
以下功能可以完成这项工作,但更短更甜的版本(LINQ?)会很棒:
Dictionary<int, string[]> MergeArrays( IEnumerable<int> idCollection,
params IEnumerable<string>[] valueCollections )
{
var dict = new Dictionary<int, string[]>();
var idL = idCollection.Count();
while ( idL-- > 0 )
{
dict[idCollection.ElementAt( idL )] = new string[valueCollections.Length];
var vL = valueCollections.Length;
while ( vL-- > 0 )
dict[idCollection.ElementAt( idL )][vL] = valueCollections[vL].ElementAt( idL );
}
return dict;
}
有什么想法吗?
答案 0 :(得分:3)
目前这是非常无效的 - 所有这些对ElementAt的调用每次都可以通过整个序列(只要他们需要)。 (这取决于序列的实现。)
然而,我完全不确定我是否理解这段代码正在做什么(使用foreach循环几乎肯定会使它更清晰,就像向前而不是向后迭代一样。你能给出一些样本输入吗?和预期的输出?
编辑:好的,我想我知道这里发生了什么;你有效地转移了valueCollections。我怀疑你会想要这样的东西:static Dictionary<int, string[]> MergeArrays(
IEnumerable<int> idCollection,
params IEnumerable<string>[] valueCollections)
{
var valueCollectionArrays = valueCollections.Select
(x => x.ToArray()).ToArray();
var indexedIds = idCollection.Select((Id, Index) => new { Index, Id });
return indexedIds.ToDictionary(x => Id,
x => valueCollectionArrays.Select(array => array[x.Index]).ToArray());
}
虽然这很难看。如果你可以让idCollection成为一个数组,那么坦率地说就更容易了。
编辑:好的,假设我们可以改为使用数组:
static Dictionary<int, string[]> MergeArrays(
int[] idCollection,
params string[][] valueCollections)
{
var ret = new Dictionary<int, string[]>();
for (int i=0; i < idCollection.Length; i++)
{
ret[idCollection[i]] = valueCollections.Select
(array => array[i]).ToArray();
}
return ret;
}
我已经纠正了(希望)第一个版本中的错误 - 我对哪个值是数组而哪个不是数组感到困惑。第二个版本不是声明性的,但我认为它更清楚,个人。
答案 1 :(得分:2)
怎么样:
public static Dictionary<int, string[]> MergeArrays2(IEnumerable<int> idCollection,
params IEnumerable<string>[] valueCollections)
{
var dict = new Dictionary<int, string[]>();
var valEnums = (from v in valueCollections select v.GetEnumerator()).ToList();
foreach (int id in idCollection)
{
var strings = new List<string>();
foreach (var e in valEnums)
if (e.MoveNext())
strings.Add(e.Current);
dict.Add(id, strings.ToArray());
}
return dict;
}
或略微编辑双向飞碟的答案(它对我不起作用):
static Dictionary<int, string[]> MergeArrays_Skeet(IEnumerable<int> idCollection,params IEnumerable<string>[] valueCollections)
{
var valueCollectionArrays = valueCollections.Select(x=>x.ToArray()).ToArray();
var indexedIds = idCollection.Select((Id, Index) => new { Index, Id });
return indexedIds.ToDictionary(x => x.Id,x => valueCollectionArrays.Select(array => array[x.Index]).ToArray());
}
答案 2 :(得分:1)
除非我遗漏了某些东西,否则你不需要代码来复制数组 - 它们本身就是对象,并且不会意外消失。
使用Select()
使用匿名类将值组合在一起,然后ToDictionary()
将它们组合起来。
试试这个:
IDictionary<int, IEnumerable<string>> MergeArrays2(
IEnumerable<int> idCollection,
params IEnumerable<string>[] valueCollections)
{
var values = valueCollections.ToList();
return idCollection.Select(
(id, index) => new { Key = id, Value = values[index] })
.ToDictionary(x => x.Key, x => x.Value);
}
注意返回类型使用IEnumerable而不是string [] - 恕我直言,你会发现这比使用数组更灵活。
此外,返回类型使用的是接口。
更新:John Skeet提出了一个很好的观点(见下面的评论)数组是可变的,这可能是一个问题。请参阅下文,以便轻松更改以创建新阵列:
IDictionary<int, IEnumerable<string>> MergeArrays2(
IEnumerable<int> idCollection,
params IEnumerable<string>[] valueCollections)
{
var values = valueCollections.ToList();
return idCollection.Select(
(id, index) => new
{
Key = id,
Value = values[index].ToArray() // Make new array with values
})
.ToDictionary(x => x.Key, x => x.Value);
}
答案 3 :(得分:1)
这里有一些优雅。它比我喜欢的时间长,但它是可以探索的。
public Dictionary<int, string[]> MergeArrays(
IEnumerable<int> idCollection,
params IEnumerable<string>[] valueCollections
)
{
Dictionary<int, int> ids = idCollection
.ToDictionaryByIndex();
//
Dictionary<int, List<string>> values =
valueCollections.Select(x => x.ToList())
.ToList()
.Pivot()
.ToDictionaryByIndex();
//
Dictionary<int, string[]> result =
ids.ToDictionary(
z => z.Value,
z => values[z.Key].ToArray()
);
return result;
}
这是我使用的辅助方法。
public static List<List<T>> Pivot<T>
(this List<List<T>> source)
{
return source
.SelectMany((it) =>
it.Select((t, i) => new { t, i })
)
.GroupBy(z => z.i)
.Select(g => g.Select(z => z.t).ToList())
.ToList();
}
public static Dictionary<int, T> ToDictionaryByIndex<T>
(this IEnumerable<T> source)
{
return source
.Select((t, i) => new { t, i })
.ToDictionary(z => z.i, z => z.t);
}
免责声明:如果您使用非矩形结构调用Pivot,我不知道/关心会发生什么。
答案 4 :(得分:0)
这并不像你要求的那样一般,但它将两个枚举连接成一个可枚举的对。将该结果可枚举为字典非常简单。
public static class ExtensionMethods
{
public static IEnumerable<Pair<TOuter, TInner>> InnerPair<TInner, TOuter>(this IEnumerable<TOuter> master,
IEnumerable<TInner> minor)
{
if (master == null)
throw new ArgumentNullException("master");
if (minor == null)
throw new ArgumentNullException("minor");
return InnerPairIterator(master, minor);
}
public static IEnumerable<Pair<TOuter, TInner>> InnerPairIterator<TOuter, TInner>(IEnumerable<TOuter> master,
IEnumerable<TInner> minor)
{
IEnumerator<TOuter> imaster = master.GetEnumerator();
IEnumerator<TInner> iminor = minor.GetEnumerator();
while (imaster.MoveNext() && iminor.MoveNext())
{
yield return
new Pair<TOuter, TInner> { First = imaster.Current, Second = iminor.Current };
}
}
}
public class Pair<TFirst, TSecond>
{
public TFirst First { get; set; }
public TSecond Second { get; set; }
}