Related
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();
}
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;
}
I have a single array with these entries:
{1, 1, 2, 2, 3,3,3, 4}
and i want to transform them to ( 3 lists in this case ):
{1,2,3,4}
{1,2,3}
{3}
Is there any way to do this with LINQ or SQL? I guess there's a mathematical term for this operation, which I don't know unfortunately...
Or do I have to do it with loops?
=======
EDIT: I can't really describe the logic, so here are more examples.. It more or less loops multiple times over the array and takes every number once ( but every number only once per round ) until there are no numbers left
{1, 1, 2, 2, 3,3,3, 4, 5}
would be
{1,2,3,4,5}
{1,2,3}
{3}
or
{1, 1, 2, 2,2, 3,3,3, 4, 5}
would be
{1,2,3,4,5}
{1,2,3}
{2,3}
private IEnumerable<List<int>> FooSplit(IEnumerable<int> items)
{
List<int> source = new List<int>(items);
while (source.Any())
{
var result = source.Distinct().ToList();
yield return result;
result.ForEach(item => source.Remove(item));
}
}
Usage:
int[] items = { 1, 1, 2, 2, 3, 3, 3, 4 };
foreach(var subList in FooSplit(items))
{
// here you have your three sublists
}
Here is another solution, which is less readable but it will have better performance:
private IEnumerable<IEnumerable<int>> FooSplit(IEnumerable<int> items)
{
var groups = items.GroupBy(i => i).Select(g => g.ToList()).ToList();
while (groups.Count > 0)
{
yield return groups.Select( g =>
{ var i = g[0]; g.RemoveAt(g.Count - 1); return i; });
groups.RemoveAll(g => g.Count == 0);
}
}
this does the job:
static void Main(string[] args)
{
int[] numbers = {1, 1, 2, 2, 3, 3, 3, 3, 4, 5, 5};
List<int> nums = new List<int>(numbers.Length);
nums.AddRange(numbers);
while (nums.Count > 0)
{
int[] n = nums.Distinct().ToArray();
for (int i = 0; i < n.Count(); i++)
{
Console.Write("{0}\t", n[i]);
nums.Remove(n[i]);
}
Console.WriteLine();
}
Console.Read();
}
Here's an alternative console app:
class Program
{
class Freq
{
public int Num { get; set; }
public int Count { get; set; }
}
static void Main(string[] args)
{
var nums = new[] { 1, 1, 2, 2, 3, 3, 3, 4 };
var groups = nums.GroupBy(i => i).Select(g => new Freq { Num = g.Key, Count = g.Count() }).ToList();
while (groups.Any(g => g.Count > 0))
{
var list = groups.Where(g => g.Count > 0).Select(g => g.Num).ToList();
list.ForEach(li => groups.First(g => g.Num == li).Count--);
Console.WriteLine(String.Join(",", list));
}
Console.ReadKey();
}
}
I am new to C# and hope I can get some help on this topic. I have an array with elements and I need to display how many times every item appears.
For instance, in [1, 2, 3, 4, 4, 4, 3], 1 appears one time, 4 appears three times, and so on.
I have done the following but don`t know how to put it in the foreach/if statement...
int[] List = new int[]{1,2,3,4,5,4,4,3};
foreach(int d in List)
{
if("here I want to check for the elements")
}
Thanks you, and sorry if this is a very basic one...
You can handle this via Enumerable.GroupBy. I recommend looking at the C# LINQ samples section on Count and GroupBy for guidance.
In your case, this can be:
int[] values = new []{1,2,3,4,5,4,4,3};
var groups = values.GroupBy(v => v);
foreach(var group in groups)
Console.WriteLine("Value {0} has {1} items", group.Key, group.Count());
You can keep a Dictionary of items found as well as their associated counts. In the example below, dict[d] refers to an element by its value. For example d = 4.
int[] List = new int[]{1,2,3,4,5,4,4,3};
var dict = new Dictionary<int, int>();
foreach(int d in List)
{
if (dict.ContainsKey(d))
dict[d]++;
else
dict.Add(d, 1);
}
When the foreach loop terminates you'll have one entry per unique value in dict. You can get the count of each item by accessing dict[d], where d is some integer value from your original list.
The LINQ answers are nice, but if you're trying to do it yourself:
int[] numberFound = new int[6];
int[] List = new int[] { 1, 2, 3, 4, 5, 4, 4, 3 };
foreach (int d in List)
{
numberFound[d]++;
}
var list = new int[] { 1, 2, 3, 4, 5, 4, 4, 3 };
var groups = list.GroupBy(i => i).Select(i => new { Number = i.Key, Count = i.Count() });
private static void CalculateNumberOfOccurenceSingleLoop()
{
int[] intergernumberArrays = { 1, 2, 3, 4, 1, 2, 4, 1, 2, 3, 5, 6, 1, 2, 1, 1, 2 };
Dictionary<int, int> NumberOccurence = new Dictionary<int, int>();
for (int i = 0; i < intergernumberArrays.Length; i++)
{
if (NumberOccurence.ContainsKey(intergernumberArrays[i]))
{
var KeyValue = NumberOccurence.Where(j => j.Key == intergernumberArrays[i]).FirstOrDefault().Value;
NumberOccurence[intergernumberArrays[i]] = KeyValue + 1;
}
else
{
NumberOccurence.Add(intergernumberArrays[i], 1);
}
}
foreach (KeyValuePair<int, int> item in NumberOccurence)
{
Console.WriteLine(item.Key + " " + item.Value);
}
Console.ReadLine();
}
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;
}