Reading linkedlists - c#

Can I read two linked-lists in one foreach?
How can I do it?
This is my code:
LinkedList<Double> estimatedProxiSize = new LinkedList<Double>();
LinkedList<Double> planAddedAndModifiedSize = new LinkedList<Double>();
estimatedProxiSize.AddLast(Convert.ToDouble(130));
estimatedProxiSize.AddLast(Convert.ToDouble(650));
estimatedProxiSize.AddLast(Convert.ToDouble(99));
estimatedProxiSize.AddLast(Convert.ToDouble(150));
estimatedProxiSize.AddLast(Convert.ToDouble(128));
planAddedAndModifiedSize.AddLast(Convert.ToDouble(163));
planAddedAndModifiedSize.AddLast(Convert.ToDouble(765));
planAddedAndModifiedSize.AddLast(Convert.ToDouble(141));
planAddedAndModifiedSize.AddLast(Convert.ToDouble(166));
planAddedAndModifiedSize.AddLast(Convert.ToDouble(137));
calc(listaX,listaY);
public void calc(LinkedList<Double> listaX, LinkedList<Double> listaY)
{
//Here, I need something like:
foreach (var itemx in listaX and var itemy)
{
Double xy = itemx*itemxy;
}
}
Is it possible?
Or is there a better way to do it?

If both LinkedList(T) are the same size then Enumerable.Zip will work.
Otherwise you can roll your own:
public static class EnumerableExtensions
{
public static IEnumerable<TResult> Zip<T, TResult>(
this IEnumerable<T> first,
IEnumerable<T> second,
Func<T, T, TResult> resultSelector
)
{
using(var firstEnumerator = first.GetEnumerator())
using(var secondEnumerator = second.GetEnumerator())
{
while(firstEnumerator.MoveNext() && secondEnumerator.MoveNext())
{
yield return resultSelector(firstEnumerator.Current,
secondEnumerator.Current);
}
}
}
}
Usage:
foreach(var item in listaX.Zip(listaY, (x, y) => x * y)
{
}

You can use Zip to combine the items from each list that are in the same position into a single object, and then iterate that resulting sequence:
var zipped = listaX.Zip(listaY, (x, y)=>new{x,y});
foreach(var pair in zipped)
{
double product = pair.x * pair.y;
}
Or, to simplify a bit to this specific case:
var products = listaX.Zip(listaY, (x, y) => x * y);
foreach(double product in products)
{
//do stuff with product
}

If estimatedProxiSize and planAddedAndModifiedSize have the same number of elements you can use IEnumrable<T>.Zip:
estimatedProxiSize.Zip(planAddedAndModifiedSize,(estim,plan)=> estim * plan));

Related

What is the best, more practical way to write such an entry with nested dictionaries? Which design pattern to use? C#

There is a lot of data in the database, and it is necessary to produce statistics (find the average number of each operation per day by each user of the application) using c # collections. In my opinion, it is necessary to use dictionaries:
var dict = new Dictionary<long?, Dictionary<DateTime, Dictionary<OperationsGroupType, int>>>();
Please advise a more practical way to write it. As it looks strange. Thank you
I wrote a function:
public void D()
{
var dict = new Dictionary<long?, Dictionary<DateTime, Dictionary<OperationsGroupType, int>>>();
int pageNumber = 0;
int pageSize = 5;
int pageCount = 1;
while (pageNumber < pageCount)
{
int count;
foreach (OperationData op in OperationService.GetPage(pageNumber, pageSize, out count))
if(op.PerformedBy.HasValue)
if(op.PerformedDate.HasValue)
if (dict.ContainsKey(op.PerformedBy))
if (dict[op.PerformedBy].ContainsKey(op.PerformedDate.Value.Date.Date))
if (dict[op.PerformedBy][op.PerformedDate.Value.Date.Date.Date.Date].ContainsKey(op.Type)) dict[op.PerformedBy][op.PerformedDate.Value.Date.Date.Date.Date][op.Type]++;
else dict[op.PerformedBy][op.PerformedDate.Value.Date.Date.Date.Date].Add(op.Type, 1);
else dict[op.PerformedBy].Add(op.PerformedDate.Value.Date.Date.Date.Date, new Dictionary<OperationsGroupType, int> { { op.Type, 1 } });
else dict.Add(op.PerformedBy, new Dictionary<DateTime, Dictionary<OperationsGroupType, int>> { { op.PerformedDate.Value.Date.Date.Date.Date, new Dictionary<OperationsGroupType, int> { { op.Type, 1 } } } });
pageCount = (count - 1) / pageSize + 1;
pageNumber++;
}
foreach (var item in dict)
{
var opDateDict = new Dictionary<DateTime, int>();
foreach (var operDate in item.Value) opDateDict.Add(operDate.Key, operDate.Value.Sum(count => count.Value));
SystemLogger.Instance.WriteErrorTrace(String.Format("Average number of user operations {0} per day: {1}\n", item.Key, opDateDict.Values.Sum() / opDateDict.Count));
}
}
OperationsGroupType - this enum
Please tell me how to replace the dictionary with a more practical design?
Which pattern is best for solving this problem?
It's terribly difficult to say what's best or most practical - and that's because you didn't really define what you mean by "best" or "practical".
I'm going to define them as minimal code and minimal repetition.
To start with I created these extension methods:
public static class Ex
{
public static R Ensure<T, R>(this Dictionary<T, R> #this, T key) where R : new
{
if (#this.ContainsKey(key))
return #this[key];
else
{
var r = new R();
#this[key] = r;
return r;
}
}
public static R Ensure<T, R>(this Dictionary<T, R> #this, T key, Func<R> factory)
{
if (#this.ContainsKey(key))
return #this[key];
else
{
var r = factory();
#this[key] = r;
return r;
}
}
}
With those I can rewrite you code like this:
foreach (OperationData op in OperationService.GetPage(pageNumber, pageSize, out count))
{
if (op.PerformedBy.HasValue)
if (op.PerformedDate.HasValue)
{
dict.Ensure(op.PerformedBy).Ensure(op.PerformedDate.Value.Date).Ensure(op.Type, () => 0);
dict[op.PerformedBy][op.PerformedDate.Value.Date][op.Type]++;
}
}

Select items with a frequency of 1 from a List<T> using LINQ

I have a list of Point classes.
Two of the points are repeated only once in the list and the rest are repeated twice.
How can I find the points that have been repeated once using LINQ?
This solution will group identical points together, allowing you to find the groups with only one member, and return that member.
I haven't checked the actual runtime, but there's a good chance that it's better, performance-wise, than a solution which involves running a Count() operation inside a Where, since that would probably run at O(n^2) time, whereas the GroupBy implementation probably does it more elegantly.
var result = points
.GroupBy(p => p)
.Where(group => group.Count() == 1)
.Select(group => group.First());
using System;
using System.Collections.Generic;
using System.Linq;
class Point
{
int x, y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
public int X
{
get { return x; }
set { x = value; }
}
public int Y
{
get { return y; }
set { y = value; }
}
}
class Test
{
static void Main()
{
var collection = new List<Point>
{
new Point(1,1),
new Point(1,2),
new Point(1,1),
new Point(1,2),
new Point(3,3),
new Point(4,5),
};
var result = collection.Where(a => collection.Count(b => b.X == a.X && b.Y == a.Y) == 1);
foreach (var val in result)
Console.WriteLine(val.X + "," + val.Y);
}
}
//output:
3,3
4,5
Try this :
var result = points.Where(p1 => points.Count(p2 => p1.Contains(p2)) == 1);

linq to sql remove URLS that starts with same domain

I have a list of URLS in a data table. I want to remove rows that starts with same domain. Right now I have this code:
List<int> toRemove = new List<int>();
toRemove.Clear();
string initialDomain;
string compareDomainName;
for(int i = 0; i<UrlList.Rows.Count -1; i++)
{
if (toRemove.Contains(i))
continue;
initialDomain = new Uri(UrlList.Rows[i][0] as String).Host;
for(int j = i + 1; j < UrlList.Rows.Count; j++)
{
compareDomainName = new Uri(UrlList.Rows[j][0] as String).Host;
if (String.Compare(initialDomain, compareDomainName, true) == 0)
{
toRemove.Add(j);
}
}
percent = i * 100 / total;
if (percent > lastPercent)
{
progress.EditValue = percent;
Application.DoEvents();
lastPercent = percent;
}
}
for(int i = toRemove.Count-1; i>=0; i--)
{
UrlList.Rows.RemoveAt(toRemove[i]);
}
It works well for small amount of data, but when I load a long list of URLs it is very slow. Now I want to move to linq, but I do not know how to realize this using linq. Any help?
Update *
I do not need to remove eduplicate rows. For ex.
I have a list of URLS
Now, I know how to remove duplicate rows. My problem is:
I have a simple list of urls:
http://centroid.steven.centricagency.com/forms/contact-us?page=1544
http://chirp.wildcenter.org/poll
http://itdiscover.com/links/
http://itdiscover.com/links/?page=132
http://itdiscover.com/links/?page=2
http://itdiscover.com/links/?page=3
http://itdiscover.com/links/?page=4
http://itdiscover.com/links/?page=6
http://itdiscover.com/links/?page=8
http://www.foreignpolicy.com/articles/2010/06/21/la_vie_en
http://www.foreignpolicy.com/articles/2010/06/21/the_worst_of_the_worst
http://www.foreignpolicy.com/articles/2011/04/25/think_again_dictators
http://www.foreignpolicy.com/articles/2011/08/22/the_dictators_survival_guide
http://www.gsioutdoors.com/activities/pdp/glacier_ss_nesting_wine_glass/gourmet_backpacking/
http://www.gsioutdoors.com/products/pdp/telescoping_foon_orange/
http://www.gsioutdoors.com/products/pdp/telescoping_spoon_blue/
now I want this list:
http://centroid.steven.centricagency.com/forms/contact-us?page=1544
http://chirp.wildcenter.org/poll
http://itdiscover.com/links/
http://www.foreignpolicy.com/articles/2010/06/21/la_vie_en
http://www.gsioutdoors.com/activities/pdp/glacier_ss_nesting_wine_glass/gourmet_backpacking/
var result = urls.Distinct(new UrlComparer());
public class UrlComparer : IEqualityComparer<string>
{
public bool Equals(string x, string y)
{
return new Uri(x).Host == new Uri(y).Host;
}
public int GetHashCode(string obj)
{
return new Uri(obj).Host.GetHashCode();
}
}
You can also implement an extension method DistinctBy
public static partial class MyExtensions
{
public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector)
{
HashSet<TKey> knownKeys = new HashSet<TKey>();
return source.Where(x => knownKeys.Add(keySelector(x)));
}
}
var result = urls.DistinctBy(url => new Uri(url).Host);
Try to use this:
IEnumerable<string> DeleteDuplicates(IEnumerable<string> source)
{
var hosts = new HashSet<string>();
foreach (var s in source)
{
var host = new Uri(s).Host.ToLower();
if (hosts.Contains(host))
continue;
hosts.Add(host);
yield return s;
}
}
Hi implement this function to remove the duplicate rows
public DataTable FilterURLS(DataTable urllist)
{
return
(from urlrow in urllist.Rows.OfType<DataRow>()
group urlrow by urlrow.Field<string>("Host") into g
select g
.OrderBy(r => r.Field<int>("ID"))
.First()).CopyToDataTable();
}

using LINQ to find the cumulative sum of an array of numbers in C#

I have a csv string containing doubles (e.g "0.3,0.4,0.3"), and I want to be able to output a double array containing the cumulative sum of these numbers (e.g [0.3,0.7,1.0]).
So far, I have
double[] probabilities = textBox_f.Text.Split(new char[]{','}).Select(s => double.Parse(s)).ToArray();
which gives the numbers as an array, but not the cumulative sum of the numbers.
Is there any way to continue this expression to get what I want, or do I need to use iteration to create a new array from the array I already have?
There's a time for generality, and there's a time for solving the problem actually posed. This is one of the latter times. If you want to make a method that turns a sequence of doubles into a sequence of partial sums, then just do that:
public static IEnumerable<double> CumulativeSum(this IEnumerable<double> sequence)
{
double sum = 0;
foreach(var item in sequence)
{
sum += item;
yield return sum;
}
}
Easy. No messing around with aggregates and complicated queries and whatnot. Easy to understand, easy to debug, easy to use:
textBox_f.Text
.Split(new char[]{','})
.Select(s => double.Parse(s))
.CumulativeSum()
.ToArray();
Now, I note that if that is user input then double.Parse can throw an exception; it might be a better idea to do something like:
public static double? MyParseDouble(this string s)
{
double d;
if (double.TryParse(s, out d))
return d;
return null;
}
public static IEnumerable<double?> CumulativeSum(this IEnumerable<double?> sequence)
{
double? sum = 0;
foreach(var item in sequence)
{
sum += item;
yield return sum;
}
}
...
textBox_f.Text
.Split(new char[]{','})
.Select(s => s.MyParseDouble())
.CumulativeSum()
.ToArray();
and now you don't get an exception if the user makes a typing mistake; you get nulls.
I had a similar requirement some time ago. Basically, I needed to do an aggregation, but I also needed to select each intermediate value. So I wrote an extension method named SelectAggregate (probably not the most appropriate name, but I couldn't find anything better then) that can be used like that:
double[] numbers = new [] { 0.3, 0.4, 0.3 };
double[] cumulativeSums = numbers.SelectAggregate(0.0, (acc, x) => acc + x).ToArray();
Here's the code :
public static IEnumerable<TAccumulate> SelectAggregate<TSource, TAccumulate>(
this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func)
{
source.CheckArgumentNull("source");
func.CheckArgumentNull("func");
return source.SelectAggregateIterator(seed, func);
}
private static IEnumerable<TAccumulate> SelectAggregateIterator<TSource, TAccumulate>(
this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func)
{
TAccumulate previous = seed;
foreach (var item in source)
{
TAccumulate result = func(previous, item);
previous = result;
yield return result;
}
}
You want to use the Aggregate operator, with a List<double> as the aggregation accumulator. That way you can produce a projection which is itself a sequence of sums.
Here's an example to get you started:
double[] runningTotal = textBox_f.Text
.Split(new char[]{','})
.Select(s => double.Parse(s))
.Aggregate((IEnumerable<double>)new List<double>(),
(a,i) => a.Concat(new[]{a.LastOrDefault() + i}))
.ToArray();
var input=new double[]{ ... }
double sum=0;
var output=input
.Select(w=>sum+=w);
Why does it need to be LINQ?
var cumulative = new double[probabilities.Length];
for (int i = 0; i < probabilities.Length; i++)
cumulative[i] = probabilities[i] + (i == 0 ? 0 : cumulative[i-1]);
First of all i don't think that it is good task for Linq. Plain old foreach will do it better. But as a puzzle it is fine.
First idea was to use subqueries, but i don't like it, because it is O(n^2). Here is my linear solution:
double[] probabilities = new double[] { 0.3, 0.4, 0.3};
probabilities
.Aggregate(
new {sum=Enumerable.Empty<double>(), last = 0.0d},
(a, c) => new {
sum = a.sum.Concat(Enumerable.Repeat(a.last+c,1)),
last = a.last + c
},
a => a.sum
);
use RX :
var input=new double[]{ ... }
var output = new List<double>();
input.ToObservable().Scan((e, f) => f + e).Subscribe(output.Add);
This is actually pretty straightforward to generalize using generator. Here is a new extension method called Accumulate that works like a combination of Select and Aggregate. It returns a new sequence by applying a binary function to each element in the sequence and accumulated value so far.
public static class EnumerableHelpers
{
public static IEnumerable<U> Accumulate<T, U>(this IEnumerable<T> self, U init, Func<U, T, U> f)
{
foreach (var x in self)
yield return init = f(init, x);
}
public static IEnumerable<T> Accumulate<T>(this IEnumerable<T> self, Func<T, T, T> f)
{
return self.Accumulate(default(T), f);
}
public static IEnumerable<double> PartialSums(this IEnumerable<double> self)
{
return self.Accumulate((x, y) => x + y);
}
public static IEnumerable<int> PartialSums(this IEnumerable<int> self)
{
return self.Accumulate((x, y) => x + y);
}
}
Here's my solution:
Linq
linear time
linear memory
no side effects
Only caveat is that it doesn't work for empty lists (trivial to handle).
var doublesSummed = doubles.Skip(1).Aggregate(
new {
sum = doubles.First(),
doubles = new [] {doubles.First()}.AsEnumerable()
},
(acc, nextDouble) => new {
sum = acc.sum + nextDouble,
doubles = acc.doubles.Append(acc.sum + nextDouble)
}
);
Demo
Here's a way of doing it using LINQ:
double[] doubles = { 1.7, 2.3, 1.9, 4.1, 2.9 };
var doublesSummed = new List<double>();
Enumerable.Aggregate(doubles, (runningSum, nextFactor) => {
double currentSum = runningSum + nextFactor;
doublesSummed.Add(currentSum);
return currentSum;
});
doublesSummed.Dump();
In LINQPad:
4
5.9
10
12.9
Cumulative sum for List<double>:
var nums = new List<double>() { 0.3, 0.0, 0.4, 1.1 };
var cumsum = nums.Aggregate(new List<double> (),
(list, next) => { list.Add(list.LastOrDefault() + next); return list; });

Extension Method on IEnumerable

What is the solution for writing extension method dor IEumerable which resurns for example sum of squarea of elemetns
for example for:
IList<double> L = new List<double>();
L.Add(1);
L.Add(2);
L.Add(3);
var result = L.MyMethod();
expected value of result is 1*1 + 2*2 + 3*3 = 14
You don't need an extension method. You can just say
var sumOfSquares = list.Sum(x => x * x);
Obviously you can make it an extension method with
public static class EnumerableDoubleExtensions {
public static double SumSquares(this IEnumerable<double> source) {
Contract.Requires(source != null);
return source.Sum(x => x * x);
}
}
To do product you just say
list.Aggregate(1d, (p, x) => p * x);
which you can easily make an extension method via
public static class EnumerableDoubleExtensions {
public static double Product(this IEnumerable<double> source) {
Contract.Requires(source != null);
return source.Aggregate(1d, (p, x) => p * x);
}
}
Note that this uses Enumerable.Aggregate of which Enumerable.Sum is a special case.
The easiest way would be to use the overload of Enumerable.Sum that sums up a sequence of projected values from a sequence:
public static double GetSumOfSquares(this IEnumerable<double> numbers)
{
if(numbers == null)
throw new ArgumentNullException("numbers");
return numbers.Sum(x => x * x);
}
Do note that this will return 0D for an empty sequence. This is similar to:
numbers.Select(x => x * x)
.Sum();
As for your question about multiplying them, you could use Enumerable.Aggregate, which is a more general operator for performing accumulation-operations on sequences:
double product = numbers.Aggregate((productSoFar, next) => productSoFar * next);
This will throw an InvalidOperationException if the sequence is empty. If you would like to return something else in this case, use the overload that accepts an initial seed.

Categories