I got this operation:
let lines = (0..<linesCount).map({ _ in "\n" }).reduce("", +)
lineCount is an integer.
How can I convert this code to C#?
I have written something with Enumerable.Range(1, linesCount) and .Select(...) linked to .Aggregate(...) but I don't know what to put in (...) to get the exact same result as the Swift line.
Please try this code:
var linesCount = 4;
var lines = Enumerable
.Range(1, linesCount)
.Select(i => "\n")
.Aggregate((c, n) => $"{c}{n}");
However if you only need to create a string of single char that repeated several times you can use string constructor:
var lines = new string('\n', linesCount);
MapReduce in C#
Map in C#
static void Main(string[] args)
{
var testList = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var mapList = Map<int, int>(x => x + 2, testList);
mapList.ToList<int>().ForEach(i => Console.Write(i + " "));
Console.WriteLine();
Console.ReadKey();
}
static IEnumerable<TResult> Map<T, TResult>(Func<T,TResult> func,
IEnumerable<T> list)
{
foreach (var i in list)
yield return func(i);
}
Reduce in C#
static void Main(string[] args)
{
var testList = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Console.WriteLine(Reduce<int, int>((x, y) => x + y, testList, 0));
Console.ReadKey();
}
static T Reduce<T, U>(Func<U, T, T> func, IEnumerable<U> list, T acc)
{
foreach (var i in list)
acc = func(i, acc);
return acc;
}
Related
We often need a way to compare the items of two lists and find which items exists only in ListA (leftOuterItems), which exist only in ListB (rightOuterItems) and their common items (matchedItems)...
I've ended up with two solutions as you can see below:
One way is to sort the lists and iterate one by one (which has a performance penalty when the collections have too many items due to sorting), and the other way is to use dictionaries and hashing (which is slower than the first way when collections have a few items - due to memory allocation etc)
*Also keep in mind that I want to compare two lists of objects eg two lists of class Person (not just primitives).. That's why I created generic extension methods
So, do you have any better idea to suggest?
Thank you in advanced!
class Program
{
static void Main(string[] args)
{
var fewItemsList1 = new[] { 1, 4, 2, 3, 7, 6, 9, 5 };
var fewItemsList2 = new[] { 15, 5, 14, 6, 13, 7, 12, 8, 11, 9, 10 };
Run(100_000, fewItemsList1, fewItemsList2);
var manyItemsList1 = Enumerable.Range(0, 100_000).ToArray();
var manyItemsList2 = Enumerable.Range(50000, 150_000).ToArray();
Run(1000, manyItemsList1, manyItemsList2);
Console.WriteLine("Hello World!");
Console.Read();
}
private static void Run(int count, int[] l1, int[] l2)
{
var sw = Stopwatch.StartNew();
for (int i = 0; i < count; i++)
l1.OrderedCompare(l2, x => x, x => x, out int[] leftOuterItems, out int[] rightOuterItems, out (int, int)[] matchedItems);
sw.Stop();
Console.WriteLine($"OrderedCompare for {count} iterations with L1 items:{l1.Count()} and L2 items:{l2.Count()} took {sw.Elapsed}");
sw.Restart();
for (int i = 0; i < count; i++)
l1.HashedCompare(l2, x => x, x => x, out int[] leftOuterItems2, out int[] rightOuterItems2, out (int, int)[] matchedItems2);
Console.WriteLine($"HashedCompare for {count} with L1 items:{l1.Count()} and L2 items:{l2.Count()} iterations took {sw.Elapsed}");
}
}
public static class Extensions
{
public static void OrderedCompare<T1, T2, TKey>(
this IEnumerable<T1> source,
IEnumerable<T2> target,
Func<T1, TKey> sourceKeyGetter,
Func<T2, TKey> targetKeyGetter,
out T1[] leftOuterItems,
out T2[] rightOuterItems,
out (T1, T2)[] matchedItems) where TKey : IComparable<TKey>
{
var leftOuterItemsList = new List<T1>();
var rightOuterItemsList = new List<T2>();
var matchedItemsList = new List<(T1, T2)>();
source = source.OrderBy(x => sourceKeyGetter(x)).ToArray();
target = target.OrderBy(x => targetKeyGetter(x)).ToArray();
bool reverseCompare = false;
int i = 0, j = 0, sourcZeroBasedCount = source.Count() - 1, targetZeroBaseCount = target.Count() - 1;
while (true)
{
var end = i == sourcZeroBasedCount && j == targetZeroBaseCount;
var sourceItem = source.ElementAt(i);
var targetItem = target.ElementAt(j);
var sourceKey = sourceKeyGetter(sourceItem);
var targetKey = targetKeyGetter(targetItem);
int diff = reverseCompare ? targetKey.CompareTo(sourceKey) : sourceKey.CompareTo(targetKey);
reverseCompare = i == sourcZeroBasedCount || j == targetZeroBaseCount;
switch (diff)
{
case -1:
leftOuterItemsList.Add(sourceItem);
i = i < sourcZeroBasedCount ? i + 1 : i;
break;
case 0:
matchedItemsList.Add((sourceItem, targetItem));
i = i < sourcZeroBasedCount ? i + 1 : i;
j = j < targetZeroBaseCount ? j + 1 : j;
break;
case 1:
rightOuterItemsList.Add(targetItem);
j = j < targetZeroBaseCount ? j + 1 : j;
break;
}
if (end)
break;
}
leftOuterItems = leftOuterItemsList.ToArray();
rightOuterItems = rightOuterItemsList.ToArray();
matchedItems = matchedItemsList.ToArray();
}
public static void HashedCompare<T1, T2, TKey>(
this IEnumerable<T1> source,
IEnumerable<T2> target,
Func<T1, TKey> sourceKeyGetter,
Func<T2, TKey> targetKeyGetter,
out T1[] leftOuterItems,
out T2[] rightOuterItems,
out (T1, T2)[] matchedItems) where TKey : IComparable<TKey>
{
var sourceDic = source.ToDictionary(x => sourceKeyGetter(x));
var targetDic = target.ToDictionary(x => targetKeyGetter(x));
var leftOuterKeys = sourceDic.Keys.Except(targetDic.Keys).ToArray();
var rightOuterKeys = targetDic.Keys.Except(sourceDic.Keys).ToArray();
var matchedKeys = sourceDic.Keys.Concat(targetDic.Keys).Except(leftOuterKeys.Concat(rightOuterKeys)).ToArray();
leftOuterItems = leftOuterKeys.Select(key => sourceDic[key]).ToArray();
rightOuterItems = rightOuterKeys.Select(key => targetDic[key]).ToArray();
matchedItems = matchedKeys.Select(key => (sourceDic[key], targetDic[key])).ToArray();
}
}
Most of the inefficiency in HashedCompare() is down to unnecessary enumerations and lookups in the dictionaries. If you write the algorithm in an imperative style you can avoid all that and the code becomes, in my opinion simpler to follow:
I second #00110001 suggestion that you should use a proper benchmarking framework as the differences between the different implementations are in the same order of complexity.
public static void HashedCompare<T1, T2, TKey>(
this IEnumerable<T1> source,
IEnumerable<T2> target,
Func<T1, TKey> sourceKeyGetter,
Func<T2, TKey> targetKeyGetter,
out List<T1> leftOuterItems,
out List<T2> rightOuterItems,
out List<(T1, T2)> matchedItems) where TKey : IEquatable<TKey>
{
var sourceItems = source.ToDictionary(x => sourceKeyGetter(x));
var targetItems = target.ToDictionary(x => targetKeyGetter(x));
matchedItems = new List<(T1, T2)>();
leftOuterItems = new List<T1>();
rightOuterItems = new List<T2>();
foreach (var sourceItem in sourceItems)
{
if (targetItems.TryGetValue(sourceItem.Key, out var targetItem))
matchedItems.Add((sourceItem.Value, targetItem));
else
leftOuterItems.Add(sourceItem.Value);
}
foreach (var targetItem in targetItems)
{
if (!sourceItems.ContainsKey(targetItem.Key))
rightOuterItems.Add(targetItem.Value);
}
}
You could use Except and Intersect which both work on Sets (a light weight hashset) and will work O(n) linear time complexity
var list1 = new[] { 1, 4, 2, 3, 7, 6, 9, 5 };
var List2 = new[] { 15, 5, 14, 6, 13, 7, 12, 8, 11, 9, 10 };
Console.WriteLine(string.Join(", ", list1.Except(List2)));
Console.WriteLine(string.Join(", ", List2.Except(list1)));
Console.WriteLine(string.Join(", ", List2.Intersect(list1)));
Output
1, 4, 2, 3
15, 14, 13, 12, 8, 11, 10
5, 6, 7, 9
As to whether it's faster or slower, you would have to benchmark, however my gut feeling is they will be more efficient and faster.
On the topic of benchmarking
Use a reliable tested framework like BenchmarkDotNet, you are likely to get the results wrong in unlimited ways if you roll this yourself
I have two C# Lists of different sizes e.g.
List<int> list1 = new List<int>{1,2,3,4,5,6,7};
List<int> list2 = new List<int>{4,5,6,7,8,9};
I want to use the linq Zip method to combine these two into a list of tuples that is of the size list1. Here is the resulting list I am looking for
{(1,4), (2,5), (3,6), (4,7), (5,8), (6,9), (7,0)} //this is of type List<(int,int)
Since the last item of list1 does not has a counterpart in list2, I fill up my last item of the resulting list with a default value (in this case 0 as in my case it will never appear in any of the original lists).
Is there a way I can use the linq Zip method alone to achieve this?
You can use Concat to make them both the same size, and then zip it:
var zipped = list1.Concat(Enumerable.Repeat(0,Math.Max(list2.Count-list1.Count,0)))
.Zip(list2.Concat(Enumerable.Repeat(0,Math.Max(list1.Count-list2.Count,0))),
(a,b)=>(a,b));
Or create an extension method:
public static class ZipExtension{
public static IEnumerable<TResult> Zip<TFirst,TSecond,TResult>(
this IEnumerable<TFirst> first,
IEnumerable<TSecond> second,
Func<TFirst,TSecond,TResult> func,
TFirst padder1,
TSecond padder2)
{
var firstExp = first.Concat(
Enumerable.Repeat(
padder1,
Math.Max(second.Count()-first.Count(),0)
)
);
var secExp = second.Concat(
Enumerable.Repeat(
padder2,
Math.Max(first.Count()-second.Count(),0)
)
);
return firstExp.Zip(secExp, (a,b) => func(a,b));
}
}
So you can use like this:
//last 2 arguments are the padder values for list1 and list2
var zipped = list1.Zip(list2, (a,b) => (a,b), 0, 0);
There is a useful and popular MoreLinq library. Install it and use.
using MoreLinq;
var result = list1.ZipLongest(list2, (x, y) => (x, y));
Try this using Zip function-
static void Main(string[] args)
{
List<int> firstList = new List<int>() { 1, 2, 3, 4, 5, 6, 0, 34, 56, 23 };
List<int> secondList = new List<int>() { 4, 5, 6, 7, 8, 9, 1 };
int a = firstList.Count;
int b = secondList.Count;
for (int k = 0; k < (a - b); k++)
{
if(a>b)
secondList.Add(0);
else
firstList.Add(0);
}
var zipArray = firstList.Zip(secondList, (c, d) => c + " " + d);
foreach(var item in zipArray)
{
Console.WriteLine(item);
}
Console.Read();
}
Or you can try this using ZipLongest Function by installing MoreLinq nuget package-
static void Main(string[] args)
{
List<int> firstList = new List<int>() { 1, 2, 3, 4, 5, 6, 0, 34, 56, 23 };
List<int> secondList = new List<int>() { 4, 5, 6, 7, 8, 9, 1 };
var zipArray = firstList.ZipLongest(secondList, (c, d) => (c,d));
foreach (var item in zipArray)
{
Console.WriteLine(item);
}
Console.Read();
}
Try this code-
static void Main(string[] args)
{
List<int> firstList=new List<int>() { 1, 2, 3, 4, 5, 6,0,34,56,23};
List<int> secondList=new List<int>() { 4, 5, 6, 7, 8, 9,1};
int a = firstList.Count;
int b = secondList.Count;
if (a > b)
{
for(int k=0;k<(a-b);k++)
secondList.Add(0);
}
else
{
for (int k = 0; k < (b-a); k++)
firstList.Add(0);
}
for(int i=0;i<firstList.Count;i++)
{
for(int j=0;j<=secondList.Count;j++)
{
if(i==j)
Console.Write($"({Convert.ToInt32(firstList[i])},{ Convert.ToInt32(secondList[j])})" + "");
}
}
Console.Read();
}
We can do sum using arr.Sum() function. But if it is an array of arrays. How will we add all values.
suppose data is
Array/List is [[1,2,3],[3,4,5],[5,4,3]]
how will you get s1 , sum of all first index value, s2 , sum of second index value and so on using LINQ.
If you want to sum up columns' values with a help of Linq:
int[][] source = new int[][] {
new int[] { 1, 2, 3},
new int[] { 3, 4, 5},
new int[] { 5, 4, 3},
};
int maxCol = source.Max(item => item.Length);
var colsSum = Enumerable
.Range(0, maxCol)
.Select(index => source.Sum(item => item.Length > index ? item[index] : 0))
.ToArray(); // let's meaterialize into an array
Test:
Console.Write(string.Join(", ", colsSum));
Outcome:
9, 10, 11
Summing up lines' values is easier:
// [6, 12, 12]
var linesSum = source
.Select(item => item.Sum())
.ToArray();
If you want total sum:
// 30
var total = source
.Select(item => item.Sum())
.Sum();
or
// 30
var total = source
.SelectMany(item => item)
.Sum();
Use combination of Aggregate and Zip
var arrays = new[]
{
new[] { 1, 2, 3 },
new[] { 3, 4, 5 },
new[] { 5, 4, 3 }
};
var result =
arrays.Aggregate(Enumerable.Repeat(0, 3),
(total, array) => total.Zip(array, (sum, current) => sum + current));
// result = { 9, 10, 11 }
Enumerable<T>.Zip executes provided function with items of same index.
A possible LINQ based approach (which will handle variable number of columns in each row):
using System;
using System.Collections.Generic;
using System.Linq;
namespace Test
{
public class Program
{
private static IEnumerable<int> GetTotalsPerColumn(int[][] inputData)
{
var data = inputData.SelectMany(z =>
{
return z.Select((item, index) => new { item, index });
})
.GroupBy(z => z.index)
.OrderBy(z => z.Key)
.Select(y => y.Select(z => z.item).Sum()
);
return data;
}
static void Main(string[] args)
{
var inputData = new[] {
new[] { 1, 2, 3, 5},
new[] { 3, 4, 5, 6},
new[] { 5, 4, 3},
};
var values = GetTotalsPerColumn(inputData);
foreach (var value in values)
{
Console.WriteLine(value);
}
Console.ReadLine();
}
}
}
If you are happy to avoid LINQ, this is another approach you could consider.
GetTotalsPerColumn populates a Dictionary where the key is the column number, and the value is the sum.
using System;
using System.Collections.Generic;
namespace Test
{
public class Program
{
static void Main(string[] args)
{
var inputData = new[] {
new[] { 1, 2, 3, 5},
new[] { 3, 4, 5, 6},
new[] { 5, 4, 3},
};
var values = GetTotalsPerColumn(inputData);
foreach (var value in values)
{
Console.WriteLine(value.Key + " - " + value.Value);
}
Console.ReadLine();
}
private static Dictionary<int, int> GetTotalsPerColumn(int[][] inputData)
{
var values = new Dictionary<int, int>();
foreach (var line in inputData)
{
for (int i = 0; i < line.Length; i++)
{
int tempValue;
values.TryGetValue(i, out tempValue);
tempValue += line[i];
values[i] = tempValue;
}
}
return values;
}
}
}
How do I sort a List<int> {1,4,2,56,7} from smallest to largest and largest to smallest? I have tried a few things, like
List<int> sorted = Listname.Sort();
and
List<int> sorted = Listname.OrderByDescending();
but I don't understand the syntax completely.
You can use LINQ:
var smallToLarge = Listname.OrderBy(x => x);
var largeToSmall = Listname.OrderByDescending(x => x);
If you want to assign them to a list, like in the code sample in your question, you'll have to call .ToList() after each one.
class Program
{
static void Main(string[] args)
{
List<int> listOfInts = new List<int>() { 1, 4, 2, 56, 7 };
listOfInts.Sort();
foreach (int ii in listOfInts)
{
Console.WriteLine("{0}", ii);
}
Console.WriteLine("Descending ...");
listOfInts.Reverse();
foreach (int ii in listOfInts)
{
Console.WriteLine("{0}", ii);
}
Console.WriteLine("Hit any key to continue");
Console.ReadKey();
}
}
To sort by ascending and descending
List<int> ints = new List<int>() { 1, 4, 2, 56, 7 };
ints.Sort(); // by asc
ints.Reverse(); //by desc
Consider the following structure:
IEnumerable<IEnumerable<int>> collection = new[] {
new [] {1, 2, 3},
new [] {4, 5, 6},
new [] {7, 8, 9}
};
How can I enumerate this collection so that I obtain IEnumerable<int> collections made up of the first items, second items, etc.?
That is, {1, 4, 7}, {2, 5, 8}, ...
(Though the implementation I've chosen is int[] objects, assume you only have IEnumerable<int> functionality. Thanks.)
Here's an approach that uses a generator instead of recursion. There's less array construction too, so it might be faster, but that's totally conjecture.
public static IEnumerable<IEnumerable<T>> Transpose<T>(
this IEnumerable<IEnumerable<T>> #this)
{
var enumerators = #this.Select(t => t.GetEnumerator())
.Where(e => e.MoveNext());
while (enumerators.Any()) {
yield return enumerators.Select(e => e.Current);
enumerators = enumerators.Where(e => e.MoveNext());
}
}
Just my 2 cents
In pure linq:
var transpond = collection.First().Select((frow,i)=>collection.Select(row=>row.ElementAt(i)));
Or with some inpurity:
var r1 = collection.First().Select((frow, i) => collection.Select(row => row.ToArray()[i]));
Code credit goes here (untested but looks fine).
public static class LinqExtensions
{
public static IEnumerable<IEnumerable<T>> Transpose<T>(this IEnumerable<IEnumerable<T>> values)
{
if (!values.Any())
return values;
if (!values.First().Any())
return Transpose(values.Skip(1));
var x = values.First().First();
var xs = values.First().Skip(1);
var xss = values.Skip(1);
return
new[] {new[] {x}
.Concat(xss.Select(ht => ht.First()))}
.Concat(new[] { xs }
.Concat(xss.Select(ht => ht.Skip(1)))
.Transpose());
}
}
//Input: transpose [[1,2,3],[4,5,6],[7,8,9]]
//Output: [[1,4,7],[2,5,8],[3,6,9]]
var result = new[] {new[] {1, 2, 3}, new[] {4, 5, 6}, new[] {7, 8, 9}}.Transpose();
Assuming all the sequences are of the same length.
static void Main(string[] args)
{
IEnumerable<IEnumerable<int>> collection =
new[]
{
new [] {1, 2, 3},
new [] {4, 5, 6 },
new [] {7, 8, 9}
};
Console.WriteLine("\tInitial");
Print(collection);
var transposed =
Enumerable.Range(0, collection.First().Count())
.Select(i => collection.Select(j => j.ElementAt(i)));
Console.WriteLine("\tTransposed");
Print(transposed);
}
static void Print<T>(IEnumerable<IEnumerable<T>> collection)=>
Console.WriteLine(string.Join(Environment.NewLine, collection.Select(i => string.Join(" ", i))));
Gives:
Initial
1 2 3
4 5 6
7 8 9
Transposed
1 4 7
2 5 8
3 6 9
If all elements are guaranteed to be the same length, you could do this:
IEnumerable<IEnumerable<int>> Transpose(IEnumerable<IEnumerable<int>> collection)
{
var width = collection.First().Count();
var flattened = collection.SelectMany(c => c).ToArray();
var height = flattened.Length / width;
var result = new int[width][];
for (int i = 0; i < width; i++)
{
result[i] = new int[height];
for (int j = i, k = 0; j < flattened.Length; j += width, k++)
result[i][k] = flattened[j];
}
return result;
}