仕事のために書いているプログラムでレンガの壁に出くわしました。具体的にコンテキストを知る必要はありませんが、簡単に言えば、私はそれぞれ約 65 万レコードのコレクションを 2 つ持っています。
コレクション A が正しいとわかっているコレクションであり、コレクション B が間違っているとわかっているコレクションであるとします。
コレクション B には、コレクション A の要素と同じ型のプロパティを持つ複合オブジェクトが含まれています (つまり、次のようになります)。
// Where T : IComparable
IEnumerable<DateTime> A = ...; // Collection of T elements
IEnumerable<Complex> B = ...; // Collection of complex elements.
class Complex<DateTime>
{
public DateTime Time { get; set; }
.....
}
私の問題は、基本的に A を順次列挙し、A の現在の要素が B の Complex オブジェクトに存在するかどうかを確認する必要があることです。存在しない場合は、その要素をカプセル化する Complex オブジェクトを作成する必要があります (とりわけ)。
問題は、両方のリストの長さが約 650,000 要素であることに気付いたときに発生します。データセットを減らすことはできません。この 650,000 を使用する必要があります。現在、私は を使用ICollection.Contains()
しており、二分探索の (単純な) 実装を試みましたが、時間がかかりすぎます。
何か提案はありますか?
編集:それが役立つ場合、T は IComparable を実装します。EDIT2: もう少しコンテキスト: IEnumerable は、Linq To Objects を使用して DataTable から取得されます。
IEnumerable<Complex> set = set.Tbl
.Where(dbObject => dbObject.TS.CompareTo(default(DateTime)) != 0)
.Select(Func<DataRow,Complex>) // Function that wraps the DataRow in a Complex object
// Just done to make debugging a little easier so we still have a large sample but small enough that it doesn't make me grow a beard
.Take(100000)
.AsEnumerable<Complex>();
この質問がアーカイブされ、他の誰かがこの問題を解決する必要がある場合に備えて、完全を期すために、現在の実装は次のようになりました
BDataSet bSet = new BDataSet();
B_LUTableAdapter adap = new B_LUTableAdapter();
adap.Fill(bSet.B_LU);
IEnumerable<Complex> w3 = bSet.B
.Where(dbObject => dbObject.TS.CompareTo(default(DateTime)) != 0)
// Function that just wraps datarow into a complex object
.Select(Func<DataRow, Complex>)
// Just for sake of debugging speed
.Take(100000)
.AsEnumerable<Complex>();
List<Complex> b = bSet.OrderBy(x => x.Time).ToList<Complex>();
// Get last & first timestamps
// Some of the timestamps in b are 01/01/1011 for some reason,
// So we do this check.
Complex start = b.Where(x => x.Time != default(DateTime)).First();
Complex end = b.Last();
List<DateTime> a = new List<DateTime>();
// RoundSeconds reduces seconds in a DateTime to 0.
DateTime current = RoundSeconds(new DateTime(start.Time.Ticks));
while (current.CompareTo(RoundSeconds(end.Time)) <= 0)
{
a.Add(current);
current = current.Add(TimeSpan.FromMinutes(1));
}
IEnumerable<DateTime> times = b.Select(x => x.Time);
var missing = a.Where(dt => times.Contains(dt));
foreach (var dt in missing)
{
adap.Insert(dt, 0, "", "", "", null, 0, 0);
// This has since been changed to List.Add()
}
Cosmin のおかげで、この問題は解決され、完成した実装は次のとおりです。 List expected = new List(); DateTime current = RoundSeconds(new DateTime(start.Time.Ticks));
while (current.CompareTo(RoundSeconds(end.Time)) <= 0)
{
expected.Add(current);
current = current.Add(TimeSpan.FromMinutes(1));
}
Console.WriteLine("Expecting {0} intervals.", expected.Count);
var missing = b.FindAllMissing(expected, x => x.Time);
if(!missing.Any()) return;
Console.WriteLine("{0} missing intervals.", missing.Count());
foreach (var dt in missing)
{
b.Add(new Complex() { /* some values */ });
//Console.WriteLine("\t> Inserted new record at {0}", dt);
}
//.....
public static IEnumerable<Basic> FindAllMissing<Basic, Complex>(this IEnumerable<Complex> complexList,
IEnumerable<Basic> basicList,
Func<Complex, Basic> selector)
{
HashSet<Basic> inComplexList = new HashSet<Basic>();
foreach (Complex c in complexList)
inComplexList.Add(selector(c));
List<Basic> missing = new List<Basic>();
foreach (Basic basic in basicList)
if (!(inComplexList.Contains(basic)))
missing.Add(basic);
return missing;
}