In this code:
for (e = 0; e <= collection.Count - 2; e++)
{
var itm = collection.Read()
var itm_price = itm.Price
var forwards_satisfied_row = collection
.Skip(e + 1)
.SkipWhile(x => x.Price < ex_price)
.FirstOrDefault();
var backwards_satisfied_row = collection
.Reverse()
.Skip(collection.Count - e)
.SkipWhile(x => x.Price < ex_price)
.FirstOrDefault();
}
Suppose the collection contains millions of items and a Reverse() is too expensive, what would be the best way to achieve the same outcome as 'backwards_satisfied_row' ?
Edit:
For each item in the collection, it should find the first preceding item that matches the SkipWhile predicate.
For context I'm finding the distance a price extrema (minima or maxima) is from a horizontal clash with the price. This gives a 'strength' value for each Minima and Maxima, which determines the importance of it, and to help marry it up with extremas of a similar strength.
Edit 2
This chart shows the data in the reproc code below, note the dip in the middle at item #22, this item has a distance of 18.
Bear in mind this operation will be iterated millions of times.
So I'm trying not to read into memory, and to only evaluate the items needed.
When I run this on a large dataset r_ex takes 5 ms per row, whereas l_ex takes up to a second.
It might be tempting to iterate backwards and check that way, but there could be millions of previous records, being read from a binary file.
Many types of searches like Binary search wouldn't be practical here, since the values aren't ordered.
static void Main(string[] args)
{
var dict_dists = new Dictionary<Int32, Int32>();
var dict = new Dictionary<Int32, decimal> {
{1, 410},{2, 474},{3, 431},
{4, 503},{5, 461},{6, 535},
{7, 488},{8, 562},{9, 508},
{10, 582},{11, 522},{12, 593},
{13, 529},{14, 597},{15, 529},
{16, 593},{17, 522},{18, 582},
{19, 510},{20, 565},{21, 492},
{22, 544},{23, 483},{24, 557},
{25, 506},{26, 580},{27, 524},
{28, 598},{29, 537},{30, 609},
{31, 543},{32, 612},{33, 542},
{34, 607},{35, 534},{36, 594},
{37, 518},{38, 572},{39, 496},
{40, 544},{41, 469},{42, 511},
{43, 437},{44, 474},{45, 404},
{46, 462},{47, 427},{48, 485},
{49, 441},{50, 507}};
var i = 0;
for (i = 0; i <= dict.Count - 2; i++)
{
var ele = dict.ElementAt(i);
var current_time = ele.Key;
var current_price = ele.Value;
var is_maxima = current_price > dict.ElementAt(i + 1).Value;
//' If ele.Key = 23 Then here = True
var shortest_dist = Int32.MaxValue;
var l_ex = new KeyValuePair<int, decimal>();
var r_ex = new KeyValuePair<int, decimal>();
if (is_maxima)
{
l_ex = dict.Reverse().Skip(dict.Count - 1 - i + 1).SkipWhile(x => x.Value < current_price).FirstOrDefault();
r_ex = dict.Skip(i + 1).SkipWhile(x => x.Value < current_price).FirstOrDefault();
}
else
{ // 'Is Minima
l_ex = dict.Reverse().Skip(dict.Count - 1 - i + 1).SkipWhile(x => x.Value > current_price).FirstOrDefault();
r_ex = dict.Skip(i + 1).SkipWhile(x => x.Value > current_price).FirstOrDefault();
}
if (l_ex.Key > 0)
{
var l_dist = (current_time - l_ex.Key);
if ( l_dist < shortest_dist ) {
shortest_dist = l_dist;
};
}
if (r_ex.Key > 0)
{
var r_dist = (r_ex.Key - current_time);
if ( r_dist < shortest_dist ) {
shortest_dist = r_dist;
};
}
dict_dists.Add(current_time, shortest_dist);
}
var dist = dict_dists[23];
}
Edit: As a workaround I'm writing a reversed temp file for the left-seekers.
for (i = file.count - 1; i >= 0; i += -1)
{
file.SetPointerToItem(i);
temp_file.Write(file.Read());
}
You could make it more efficient by selecting the precedent of each item in one pass. Lets make an extension method for enumerables that selects a precedent for each element:
public static IEnumerable<T> SelectPrecedent<T>(this IEnumerable<T> source,
Func<T, bool> selector)
{
T selectedPrecedent = default;
foreach (var item in source)
{
if (selector(item)) selectedPrecedent = item;
yield return selectedPrecedent;
}
}
You could then use this method, and select the precedent and the subsequent of each element by doing only two Reverse operations in total:
var precedentArray = collection.SelectPrecedent(x => x.Price < ex_price).ToArray();
var subsequentArray = collection.Reverse()
.SelectPrecedent(x => x.Price < ex_price).Reverse().ToArray();
for (int i = 0; i < collection.Count; i++)
{
var current = collection[i];
var precedent = precedentArray[i];
var subsequent = subsequentArray[i];
// Do something with the current, precedent and subsequent
}
No need to do .Reverse() and then FirstOrDefault(), just use LastOrDefault(). Instead of Skip(collection.Count - e) use .Take(e) elements
var backwards_satisfied_row = collection
.SkipWhile(x => x.Price < ex_price) //Skip till x.Price < ex_price
.Skip(e+1) //Skip first e+1 elements
.LastOrDefault(); //Get Last or default value
You can make your code more efficient by storing collection and then just get FirstOrDefault() and LastOrDefault() for forwards_satisfied_row and backwards_satisfied_row respectively.
like,
for (e = 0; e <= collection.Count - 2; e++)
{
var itm = collection.Read()
var itm_price = itm.Price
var satisfied_rows = collection
.SkipWhile(x => x.Price < ex_price)
.Skip(e + 1)
.ToList();
var forwards_satisfied_row = satisfied_rows.FirstOrDefault();
var backwards_satisfied_row = satisfied_rows.LastOrDefault();
}
I have a loop that is trying to sort and organize data.
for (int a = 0; a < Combos.Count; a++)
{
//Largest to smallest
if (Combos.Count - a >= 1)
{
if (scores[a + 1] != null)
{
Combos.Add(Combos[a]);
Combos.RemoveAt(a);
scores.Add(scores[a]);
scores.RemoveAt(a);
}
}
}
I want to execute the nested if statement whenever its valid, which in java i typically use == null, however that seems to not work. Is there an exception I can use or something to check if it's out of bounds?
Instead of this
if (scores[a + 1] != null)
You check the Count(list) or Length(array):
if (a + 1 <= scores.Count)
It's not clar what you're trying to do here, but i guess there are much easier ways
//Largest to smallest
For example with LINQ:
var orderedCombos = Combos.Zip(scores, (c, s) => new{ Combo = c, Score = s})
.OrderByDescending(x => x.Score)
.Select(x => x.Combo)
.ToList();
(but you should really store both informations in the same class or at least don't link via index)
I'm beginner in c# and linq ,write this query in c#:
var query1 = (from p in behzad.Customer_Care_Database_Analysis_Centers
select p).ToArray();
for (Int64 i = 0; i < query1.Count(); i++)
{
var query2 = (from tt in behzad.Customer_Care_Database_Analysis_DETAILs
where tt.fileid == FILE_ID && tt.code_markaz ==query1[i].code_markaz //"1215" //query1[i].code_markaz.ToString().Trim() //&& tt.code_markaz.ToString().Trim() == query1[i].code_markaz.ToString().Trim()
select new
{
tt.id
}).ToArray();
if (query2.Count() > 0)
{
series1.Points.Add(new SeriesPoint(query1[i].name_markaz, new double[] { query2.Count() }));
counter += 15;
}
}//end for
but up code is very slow,i have about 1000000 Customer_Care_Database_Analysis_Centers and about 20 million record into the Customer_Care_Database_Analysis_DETAILs table,which is best query for up code?thanks.
Your current code first gets a lot of records into memory, then executes a new query for each record - where you only use the count of items, even though you again get everything.
I think (untested) that the following will perform better:
var query = from center in behzad.Customer_Care_Database_Analysis_Centers
join details in behzad.Customer_Care_Database_Analysis_DETAILs
on center.code_markaz equals details.code_markaz
where details.fileid == FILE_ID
where details.Any()
select new { Name = center.name_markaz, Count = details.Count()};
foreach(var point in query)
{
series1.Points.Add(new SeriesPoint(point.Name, new double[] { point.Count };
counter += 15;
}
Instead of a lot of queries, execute just one query that will get just the data needed
Instead of getting everything into memory first (with ToArray()), loop through it as it arrives - this saves a lot of memory
I have a string like:
one,one,one,one,two,two,two,two,three,three,three,three,four,four,four,four,...
and I'd like to delimit it after every fourth comma and store it into a list box, like this:
one,one,one,one,
two,two,two,two,
three,three,three,three,
four,four,four,four,
...
What should be appropriate way to do this? Should I supposed to use regex to somehow delimit this string?
Thanks
Linqless alternative;
int s = 0, n = 0, len = inputString.Length;
for (var i = 0; i < len; i++) {
if (inputString[i] == ',' && ++n % 4 == 0 || i == len - 1) {
aListBox.Items.Add(inputString.Substring(s, i - s + 1));
s = i + 1;
}
}
This LINQ breaks your input into individual strings by delimiting on the comma, then uses an index in the Select method to group four items together at a time, then finally joins those four items into a single string again.
var input = "one,one,one,one,two,two,two,two,three,three,three,three"; // and so on
var result = input.Split(',')
.Select((s, i) => new {s, i})
.GroupBy(pair => pair.i / 4)
.Select(grp => string.Join(",", grp.Select(pair => pair.s)) + ",");
The result is a collection of strings, where the first one (based on your input) is "one,one,one,one,", then the second is "two,two,two,two," and so on...
From there, it's just a matter of setting it as the DataSource, ItemsSource or similar, depending on what technology you're using.
Is there a way to do a segmented histrogram with linq? I've seen several examples where you can count the number of occurances of a particular object. Is it possible to create a linq based historgram that counts the number of occurances of a series of objects between two values?
I don't know how you would group by a range of items to create the buckets neccesary for a histogram? Suppose a start bound and a width are used to create the range.
You would need to iterate through the number array and group each number by whether it was <= Upper Bound and > Lower Bound. Then you would just sum each group. I have no idea how to accomplish the group by part
Something like this?
Random randF = new Random();
List<double> nums = new List<double>();
for (int i = 0; i < 100000; i++)
{
nums.Add(randF.NextDouble()*100);
}
double fromXF = 30;
double toXF = 80;
int groupCount = 10; // number of groups between values
var histF = from i in nums
let groupKeyF = ((i-fromXF)/(toXF-fromXF)*groupCount) // even distribution of "groupCount" groups between fromXF and toXF, simple math, really
where groupKeyF >= 0 && groupKeyF < groupCount // only groups we want
let groupKey = (int)groupKeyF // clamp it to only group number
group i by groupKey into gr // group it according to group number
orderby gr.Key
select new { Value = gr.Key, Count = gr.Count() };
foreach (var item in histF)
{
Console.WriteLine("Group number: " + item.Value + ", Count: " + item.Count);
}
You could do something like:
var groups = input.GroupBy(x => (int)((x.value - start)/width));
which creates an integer value for each bar and groups by that.