I've encountered a purely hypothetical problem which feels like it has an easy solution if I find the right linq method...
I have two arrays of ints and I know they are the same size. I want to create a third array of the same size where the elements in the third array are the sum of the elements in the first two arrays in the corresponding position.
Below is a method that should show what I want to do.
public static int[] AddArrays(int[] a, int[] b)
{
int[] newArray = new int[a.Length];
for (int i = 0; i<a.Length; i++)
{
newArray[i]=a[i]+b[i];
}
return newArray;
}
Are there any Linq methods that I can just use like
return a.DoStuff(b, (x,y) => x+y)
or something like that?
I should note that this probably falls in the category of homework since the original problem came from a website I was looking at (though I can't find a direct link to the problem) and not as a question I need for work or anything.
If no simple method exists then what is the most Linqy way to do this? an array.each would seem to have the problem of not being able to index the second array easily to add the values to the one you are iterating through leading me to wonder if Linq would be any help at all in that situation...
Zip it :)
var a = new int[] {1,2,3 };
var b = new int[] {4,5,6 };
a.Zip(b, (x, y) => x + y)
You can use the Select method.
int[] a = new[] { 1, 2, 3 };
int[] b = new[] { 10, 20, 30 };
var c = a.Select ((x, index) => x + b[index]).ToArray();
public static int[] AddArrays(int[] a, int[] b)
{
return a.Zip(b, (x,y) => x+y).ToArray();
}
IList<int> first = new List<int> { 2, 3, 4, 5 };
IList<int> second = new List<int> { 2, 3, 4, 5 };
var result = Enumerable.Zip(first, second, (a, b) => a + b);
Without LINQ:
private static IEnumerable<int> AddArrays(IEnumerable<int> a1, IEnumerable<int> a2)
{
var e1 = a1.GetEnumerator();
var e2 = a2.GetEnumerator();
while (e1.MoveNext() && e2.MoveNext())
yield return e1.Current + e2.Current;
}
If you have an IEnumerable<int[]> arrayCollection to sum:
arrayCollection.Aggregate((a,b) => a.Zip(b, (x,y) => x + y).ToArray())
Related
I need to write a method to find the commons between 2 arrays in C# but the thing is I can't convert my python logic from the past to C#
it used to be like this in python:
def commonfinder(list1, list2):
commonlist = []
for x in list1:
for y in list2:
if x==y:
commonlist.append(x)
return commonlist
but when I tried to convert it to C#:
public int [] Commons(int[] ar1, int[] ar2)
{
int commoncount;
int[] Commonslist = new int[commoncount];
foreach (int x in ar1)
{
foreach (int y in ar2)
{
if (x == y)
{
commoncount++;
// here I should add x to Commonlist
}
}
}
return Commonslist;
}
I couldn't find any method or functions that would append x to my Commonlist
and ofc I got a lot of errors I couldn't solve
can I get a tip?
Your original algorithm has O(n * m) time complexity, which can be too long:
imagine that you have lists of 1 million items each (1 trillion compares to perform). You can implement a better code with O(n + m) complexity only:
Code: (let's generalize the problem)
using System.Linq;
...
public static T[] CommonFinder<T>(IEnumerable<T> left,
IEnumerable<T> right,
IEqualityComparer<T> comparer = null) {
if (null == left || null == right)
return new T[0]; // Or throw ArgumentNullException exception
comparer = comparer ?? EqualityComparer<T>.Default;
Dictionary<T, int> dict = right
.GroupBy(item => item)
.ToDictionary(group => group.Key, group => group.Count());
List<T> result = new List<T>();
foreach (T item in left)
if (dict.TryGetValue(item, out int count)) {
result.Add(item);
if (count <= 1)
dict.Remove(item);
else
dict[item] = count - 1;
}
return result.ToArray();
}
Demo:
int[] left = new int[] { 1, 2, 3, 4, 5 };
int[] right = new int[] { 0, 3, 2, 6, 9};
var common = CommonFinder(left, right);
Console.WriteLine(string.Join(", ", common));
Outcome:
2, 3
Note: What I understood is you want a method that takes 2 int arrays and yields 1 int array as the output with the unique intersecting values.
You can use HashSet to speed up to insert and lookup time (amortized O(1)). The running time is O(Max(n,m)) due to us having to go through both the entire arrays (separately). In terms of memory, O(Min(n,m)) because we select the smaller array at the beginning to populate the set and for the rest of the logic naturally won't have more elements than the smaller array because it is the intersect.
The Main method shows you how to utilize the method. CommonIntegers has the logic which you seek.
using System;
using System.Collections.Generic;
using System.Linq;
namespace TestCode.StackOverflow
{
public class So66935672
{
public static void Main(string[] args)
{
int[] intArray1 = new int[] { 9, 9, 1, 3, 5, 6, 10, 9 };
int[] intArray2 = new int[] { 19, 17, 16, 5, 1, 6 };
Console.Write(
CommonIntegers(intArray1, intArray2)
.Select(i => $"{i}, ")
.Aggregate(string.Empty, string.Concat));
}
private static int[] CommonIntegers(int[] intArray1, int[] intArray2)
{
if (intArray1 == null || intArray1.Length == 0
|| intArray2 == null || intArray2.Length == 0)
{
return Array.Empty<int>();
}
var primaryArraySet = new HashSet<int>(); // Contains the unique values from the shorter array
var intersectSet = new HashSet<int>(); // Contains unique values found in both arrays
int[] secondarySet;
// Fill primary set
if (intArray1.Length > intArray2.Length)
{
foreach (var i in intArray2)
primaryArraySet.Add(i);
secondarySet = intArray1;
}
else
{
foreach (var i in intArray1)
primaryArraySet.Add(i);
secondarySet = intArray2;
}
// Fill intersect array
foreach (var i in secondarySet)
if (primaryArraySet.Contains(i))
intersectSet.Add(i);
return intersectSet.ToArray();
}
}
}
You can try this one:
static List<int> CommonFinder(List<int> list1, List<int> list2)
{
List<int> commonList = new List<int>();
foreach (int x in list1)
foreach (int y in list2)
if (x == y)
commonList.Add(x);
return commonList;
}
static void Main()
{
List<int> list1 = new List<int> { 1, 2, 3 };
List<int> list2 = new List<int> { 2, 3, 4};
var common = CommonFinder(list1, list2);
Console.WriteLine(string.Join(", ", common));
}
I have a List<List<int>[]> containing lists items e.g
List<int> a= new List<int>(){ 2, 2, 3, 4, 5};
List<int> b= new List<int>() { 2, 2, 2, 6 };
List<List<int>[]> c = new List<List<int>[]>();
c.Add(new[]{a,b});
I want to check if any of the arrays contained in c have 2 as a value . This is more or less a true or false answer.
So far I can check if a or b contains 2 using the Linq code
var result = a.Any(p=> p==2); // this outputs 2
extending this to the c
var result=c.Any(p=> p.Select(value => value.Contains(2)).First());
// the above code p=> p.Select(value => value.Contains(2)) returns an Enumerable and I take the first one. I'm not positive this is the right way to go about this problem using linq.
Is there a better way of doing this?
If you know how to search in a single list, you should be able to search in list of lists exactly the same way. Just flatten it with SelectMany and use the same criteria.
For your case, if this is for single list:
var result = a.Any(p => p == 2);
then for list of lists it would be:
var result = c.SelectMany(x => x).Any(p => p == 2);
and similar for third level as in your example:
var result = c.SelectMany(x => x).SelectMany(x => x).Any(p => p == 2);
I love PetSerAl's any any any answer but a tiny change
c.Any(x => x.Any(y => y.Contains(2)))
you need something like this:
c.Where(i=>i.Any(x=>x.Contains(2)))
List<int> a = new List<int>() { 2, 2, 3, 4, 5 };
List<int> b = new List<int>() { 2, 2, 2, 6 };
List<List<int>[]> c = new List<List<int>[]>();
c.Add(new[] { a, b });
//Lambda
bool IsValueExists = c.Any(i => i != null && i.Any(i1 => i1.Any(i2=>i2 == 2)));
//OR
//Linq
bool IsValueExists = (from i in c
from i1 in i
from i2 in i1
where i2 == 2
select i2).Any();
c.SelectMany(inner=>inner.SelectMany (i =>i )).Contains(2).Dump();
I have array of ints(Call him A) and IEnumarable(Call him B):
B - 1,2,4,8,289
A - 2,2,56,2,4,33,4,1,8,
I need to count how many times exist each number from A inside B and sum the result.
For example:
B - 1,2,4,8,289
A - 2,2,56,2,4,33,4,1,8,
result = 1+3+2+1+0
What is elegant way to implement it?
With LINQ it is easy:
int count = A
.Where(x => B.Contains(x))
.Count();
Counts how many times elements from A are contained in B.
As Yuval Itzchakov points out, this can be simplified like this:
int count = A.Count(x => B.Contains(x));
I need to count how many times exist each number from A inside B and sum the result.
You can get both the count and sum as follows
List<int> b = new List<int>() { 1,2,4,8,289 };
List<int> a = new List<int>() { 2,2,56,2,4,33,4,1,8 };
var subset = a.Where(i => b.Contains(i));
var count = subset.Count(); // 7
var sum = subset.Sum(); // 23
Note that I reuse the same Linq expression to get both the count and the sum.
One might be tempted to use a HashSet<int> in place of a List<int> because the .Contains operation is faster. However, HashSet is a set, meaning if the same number is added multiple times, only one copy of that number will remain in the set.
sweet and simple.. one line solution
why dont you try it..
int sum = 0;
A.ToList().ForEach(a=>sum +=B.Count(b=>b==a));
Console.Write(sum);
you can sweap the A/B it will still work
With Linq you can do like this
var B = new List<int>{ 1, 2, 4, 8, 289 };
var A = new List<int> { 2, 2, 56, 2, 4, 33, 4, 1, 8 };
var repetitionSum = B.Select(b => A.Count(a => a == b)).Sum(); //result = 7
And if you want, you can get the individual repetition list like this
var repetition = B.Select(b => A.Count(a => a == b)).ToList();
// { 1, 3, 2, 1, 0 }
It is not clear if you want to know the occurrences of each number or the final count (your text and your example code differ). Here is the code to get the number of appearances of each number
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
int[] a = new []{1,2,3};
int[] b = new []{1,2,2,3};
Dictionary<int, int> aDictionary = a.ToDictionary(i=>i, i => 0);
foreach(int i in b)
{
if(aDictionary.ContainsKey(i))
{
aDictionary[i]++;
}
}
foreach(KeyValuePair<int, int> kvp in aDictionary)
{
Console.WriteLine(kvp.Key + ":" + kvp.Value);
}
}
}
This question already has answers here:
c# Array.FindAllIndexOf which FindAll IndexOf
(10 answers)
Closed 8 years ago.
How to find all positions of a value in array
class Program
{
static void Main(string[] args)
{
int start = 0;
int[] numbers = new int[7] { 2,1,2,1,5,6,5};
}
Something like that:
int[] numbers = new [] { 2, 1, 2, 1, 5, 6, 5 };
int toFind = 5;
// all indexes of "5" {4, 6}
int[] indexes = numbers
.Select((v, i) => new {
value = v,
index = i
})
.Where(pair => pair.value == toFind)
.Select(pair => pair.index)
.ToArray();
List<int> indexes = new List<int>();
for (int i = 0; i < numbers.Length; i++)
{
if (numbers[i] == yourNumber)
indexes.Add(i);
}
Useage is: Array.indexOf(T,value)
please refere to the msdn below.
http://msdn.microsoft.com/en-us/library/system.array.indexof(v=vs.110).aspx
You can make a really simple extension method for sequences to do this:
public static class SequenceExt
{
public static IEnumerable<int> IndicesOfAllElementsEqualTo<T>
(
this IEnumerable<T> sequence,
T target
) where T: IEquatable<T>
{
int index = 0;
foreach (var item in sequence)
{
if (item.Equals(target))
yield return index;
++index;
}
}
}
The extension method works with List<>, arrays, IEnumerable<T> and other collections.
Then your code would look something like this:
var numbers = new [] { 2, 1, 2, 1, 5, 6, 5 };
var indices = numbers.IndicesOfAllElementsEqualTo(5); // Use extension method.
// Make indices into an array if you want, like so
// (not really necessary for this sample code):
var indexArray = indices.ToArray();
// This prints "4, 6":
Console.WriteLine(string.Join(", ", indexArray));
Linq could help
var indexes = numbers
.Select((x, idx) => new { x, idx })
.Where(c => c.x == number)
.Select(c => c.idx);
I have ordered list like in example
var someList = new List<int>{1,1,2,3,5,2,1,3,7,1};
I want to select by using LINQ best(highest sum) sequence of 3 numbers.
In this case answer is 3,7,1 or 1,3,7. Is that possible without change order or sorting?
I have an idea how to do this without LINQ, but I just wanna know to do with LINQ
You can use Skip/Zip to end up with triples. For example:
var triples = list.Zip(list.Skip(1).Zip(list.Skip(2), (b, c) => new { b, c }),
(a, bc) => new { a, bc.b, bc.c });
(That may have some errors - I haven't tested it yet.)
You can then order those triples pretty easily:
var orderedTriples = triples.OrderByDescending(t => t.a + t.b + t.c);
If you're using the triples in multiple contexts, you might want to write an extension method to use Tuple<,,> instead:
public static IEnumerable<Tuple<T, T, T>> InTriples<T>(this IEnumerable<T> source)
{
// Or potentially write custom code to do this. It wouldn't be too hard...
return source.Zip(list.Skip(1).Zip(list.Skip(2), (b, c) => new { b, c }),
(a, bc) => Tuple.Create(a, bc.b, bc.c));
}
As for whether LINQ is suitable for this - having the InTriples method generally available means that the rest of the code becomes pretty simple. Using Skip/Zip isn't going to be terribly efficient, but once you've got the code going using that, you can easily rewrite the InTriples method to use an iteerator block instead.
Alternative solution with summing into list directly, without creating triples:
var bestIndex = someList.Zip(someList.Skip(1), (a, b) => a + b)
.Zip(someList.Skip(2), (a, b) => a + b)
.Select((v, i) => new
{
Value = v,
Index = i
})
.OrderByDescending(x => x.Value )
.First()
.Index;
seems to return first highest sequence
using System;
using System.Collections.Generic;
using System.Linq;
namespace take3highestsum
{
class Program
{
static void Main(string[] args)
{
//question sequence
List<int> intlist = new List<int> { 1, 1, 2, 3, 5, 2, 1, 3, 7, 1 };
//display in console stuff not part of answer
foreach (int a in intlist)
{
Console.Write(a + " ");
}
Console.WriteLine();
//begin answer
//check for legit list since we need at least 3 elements
if (intlist.Count < 3) { throw new Exception("List must have more than 3 elements"); }
//stuff we will need
int lastindx = intlist.Count - 1, baseindex = -1;
//begin LINQ
int[] result = intlist.Select(a =>
{
baseindex++;//increment
//return each sequence of three numbers
return new int[]{
intlist[baseindex],//always base index
baseindex + 1 > lastindx ? 0 : intlist[baseindex + 1], //base index + 1 or 0 if out of bounds
baseindex + 2 > lastindx ? 0 : intlist[baseindex + 2] };//base index + 2 or 0 if out of bounds
}).OrderByDescending(b => b.Sum()).First();
//end LINQ
//end answer
//stuff to display proof
foreach (int a in result)
{
Console.Write(a);
}
Console.ReadLine();
}
}
}