LINQ: Evaluating a function where array elements are matched by index - c#

Say I have a function c[i] = f(x[i], y[i]). I have the input value arrays x and y of equal length and I want to calculate the values of array c in the end. How do I get that using LINQ?
i.e. without having to write:
c = new double[x.Length];
for (int i = 0; i < x.Length; i++)
{
c[i] = f(x[i], y[i]);
}

Use Zip method, e.g.:
int[] x = { 1, 2, 3 };
int[] y = { 4, 5, 6 };
var result = x.Zip(y, (i, j) => i + j);
or if you have already method with adequate params, simply use:
var result = x.Zip(y, Function);
// in this sample Function looks like:
static int Function(int x, int y)
{
return x + y;
}

You can use a simple Select:
var c = x.Select((x_i, i) => f(x_i, y[i]));
If c needs to be an int[] instead of IEnumerable<int>, append ToArray to the end:
var c = x.Select((x_i, i) => f(x_i, y[i])).ToArray();

You can use the Zip method to calculate
int[] a = { 4, 2, 3 };
int[] b = { 9, 1, 0 };
var result = a.Zip(b, (i, j) => i + j);

Related

Find all index numbers of a value in array [duplicate]

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);

Linq thenby running indefinitely

I have a function that is simply meant to print out a dictionary of frequent item sets in an easy-to-understand fashion. The goal is to order first by the size of the dictionary key and then by the lexicographical order of a list of numbers. The issue arises in the ThenBy statement as the commented out "hello" will get printed indefinitely. If I change the ThenBy to not use the comparer and simply use another int or string value, it works fine, so I'm clearly doing something wrong.
public static void printItemSets(Dictionary<List<int>, int> freqItemSet)
{
List<KeyValuePair<List<int>, int>> printList = freqItemSet.ToList();
printList = printList.OrderBy(x => x.Key.Count)
.ThenBy(x => x.Key, new ListComparer())
.ToList();
}
The code for the ListComparer is as follows:
public class ListComparer: IEqualityComparer<List<int>>, IComparer<List<int>>
{
public int Compare(List<int> a, List<int> b)
{
int larger = a.Count > b.Count ? 1: -1;
for (int i = 0; i < a.Count && i < b.Count; i++)
{
if (a[i] < b[i])
{
return -1;
}
else if (a[i] > b[i])
{
return 1;
}
else { }
}
return larger;
}
}
VERY simple test case:
int[] a = {1, 3, 5};
int[] b = { 2, 3, 5 };
int[] c = { 1, 2, 3, 5 };
int[] d = { 2, 5 };
int[] e = { 1, 3, 4 };
List<int> aL = a.ToList<int>();
List<int> bL = b.ToList<int>();
List<int> cL = c.ToList<int>();
List<int> dL = d.ToList<int>();
List<int> eL = e.ToList<int>();
Dictionary<List<int>, int> test = new Dictionary<List<int>, int>(new ListComparer());
test.Add(aL, 1);
test.Add(bL, 1);
test.Add(cL, 1);
test.Add(dL, 1);
test.Add(eL, 1);
The issue is that ListComparer is not checking if the arrays are the same. The same array is being passed in twice for both x and y. Checking if x and y are equal will resolve your issue.
Your comparer doesn't handle equal items. If the items are equal the order of the two items is what determines which is considered "larger". The comparer is thus not "reflexive". Being reflexive is a property sorting algorithms rely on.
The first line should be var larger = a.Count.CompareTo(b.Count); instead, so that truly equal lists will return 0 rather than either -1 or 1.

Arrange MultiDimensional arrays to descending or ascending

I am trying to arrange this multidimensional array to ascending or descending. However, I need the relation between column 1 and 2 to still be together(meaning I need the data of eg. array[0,1] and array[0,2] to be together or related in some way or another. This are my codes as of right now.
int[,] time = new int[5,2]{{0,4},{1,5},{5,10},{3,4},{0,2}};
var sorted = from x in Enumerable.Range(0, time.GetLength(0))
from y in Enumerable.Range(0, time.GetLength(1))
select new{
X = x,
Y = y,
Value = time[x,y]
}into point
orderby point.Value descending
select point;
This works but it splits all my data apart. Is there a way to sort them while keeping the relation of column 1 and 2 together?
I'm curious as to why you need a multidimensional array. It's clear you are treating your data as a single-dimensional collection of "rows," rather than a 2-dimensional collection of "cells."
Why not simply make a List(T), where T is some sort of Tuple or custom struct?
On the surface, it seems like you're trying to use a screwdriver on a nail; make sure you're picking the right tool for the job ;)
It sounds like you want to store your data in a multi-dimensional array, but keep each row in the array as a separate atomic unit. And additionally, the comparison of each "point" is by X, and then Y.
int[,] time = new int[5, 2] { { 0, 4 }, { 1, 5 }, { 5, 10 }, { 3, 4 }, { 0, 2 } };
var sorted = from x in Enumerable.Range(0, time.GetLength(0))
select new Point()
{
X = time[x,0],
Y = time[x,1]
} into point
orderby point.X ascending , point.Y ascending
select point;
int[,] sortedTime = new int[5,2];
int index = 0;
foreach (var testPoint in sorted)
{
Point aPoint = (Point) testPoint;
sortedTime.SetValue(aPoint.X, index, 0);
sortedTime.SetValue(aPoint.Y, index, 1);
index++;
}
It looks like you might just be overthinking things. If you want to keep the points together, and sort by the first column, for instance, just omit the second Enumerable.Range and assign the values by hand:
int[,] time = new int[5,2]{{0,4},{1,5},{5,10},{3,4},{0,2}};
var sorted = from x in Enumerable.Range(0, time.GetLength(0))
select new{
X = time[x,0],
Y = time[x,1]
}into point
orderby point.X descending
select point;
As #Haxx points out, just add , point.Y descending to the orderby clause if the order of the second value is also important.
I also think that one should treat this as a collection of rows since you want rows to always stay together.
.NET has the DataTable type for that. E.g.
int[,] time = new int[5, 2] { { 0, 4 }, { 1, 5 }, { 15, 10 }, { 3, 4 }, { 0, 2 } };
DataTable dt = new DataTable();
dt.Columns.Add("x", System.Type.GetType("System.Int32"));
dt.Columns.Add("y", System.Type.GetType("System.Int32"));
for (int i = 0; i < time.Length / 2; i++)
{
DataRow dr = dt.NewRow();
dr[0] = time[i, 0];
dr[1] = time[i, 1];
dt.Rows.Add(dr);
}
dt.DefaultView.Sort = "x" + " " + "ASC";
dt = dt.DefaultView.ToTable();
Note that I needed to type the table columns. Otherwise you'll get an alphabetical sort. I changed one of your numbers to 15 to demonstrate that the sort works on the integers (15>3, but alphabetically "15"<"3"). If you really want it back as a 2D array, see the first answer.
The fastest method would be to take implementation of some sorting algorithm like Quicksort and modify it to only use the Compare(i, j) and Swap(i, j) functions.
Then you can implement these functions for your multidimensional array and sort it in place.
Here is a working implementation:
public static void Main() {
int[,] time = new int[5, 2] { { 0, 4 }, { 1, 5 }, { 5, 10 }, { 3, 4 }, { 0, 2 } };
DoSort(time);
}
public static void DoSort(int[,] data) {
Func<int, int, int> comparer = (i, j) => {
int s1 = Math.Sign(data[i, 0] - data[j, 0]);
if (s1 != 0) {
return s1;
}
int s2 = Math.Sign(data[i, 1] - data[j, 1]);
return s2;
};
Action<int, int> swapper = (i, j) => {
var tmp0 = data[i, 0];
var tmp1 = data[i, 1];
data[i, 0] = data[j, 0];
data[i, 1] = data[j, 1];
data[j, 0] = tmp0;
data[j, 1] = tmp1;
};
int length = data.GetLength(0);
Quicksort(comparer, swapper, 0, length - 1);
}
public static void Quicksort(Func<int, int, int> comparer, Action<int, int> swapper, int left, int right) {
int i = left, j = right;
int pivotIdx = (left + right) / 2;
while (i <= j) {
while (comparer(i, pivotIdx) < 0) {
i++;
}
while (comparer(j, pivotIdx) > 0) {
j--;
}
if (i <= j) {
swapper(i, j);
i++;
j--;
}
}
// Recursive calls
if (left < j) {
Quicksort(comparer, swapper, left, j);
}
if (i < right) {
Quicksort(comparer, swapper, i, right);
}
}
}
This code sorts the array in-place so you need no additional memory and in the end you get a sorted multidimensional array.
Assuming:
1. You want to keep the items paired, e.g. want to treat {0, 4} as one pair, {1, 5} as another pair.
2. The expected result in ascending order is: {{0, 2}, {0, 4}, {1, 5}, {3, 4}, {5, 10}}.
As suggested by BTownTKD, strongly recommend to use some class/struct to represent your pair instead of using multidimensional array. You can use a list/array of either of the following:
Tuple<int, int>
KeyValuePair<int, int>
your own struct IntPair, having two properties X and Y.
This will not only help you to sort, but also to do further manipulations easily. Use multidimensional array only if you have a very specific need to.
Here's sample code using Tuple:
List<Tuple<int, int>> time = new List<Tuple<int, int>>(){
new Tuple<int, int>(0,4),
new Tuple<int, int>(1,5),
new Tuple<int, int>(5,10),
new Tuple<int, int>(3,4),
new Tuple<int, int>(0,2)
};
//Sort Ascending
time.Sort((first, second) =>
{
var item1Compare = first.Item1.CompareTo(second.Item1);
return item1Compare == 0 ? first.Item2.CompareTo(second.Item2) : item1Compare;
});
//Sort Descending
/*time.Sort((first, second) =>
{
var item1Compare = second.Item1.CompareTo(first.Item1);
return item1Compare == 0 ? second.Item2.CompareTo(first.Item2) : item1Compare;
});*/

LINQ to transform array [x0,y0, ..., xN, yN] into enumerable [p0, ..., pN]

Is it possible to use LINQ to transform a flat array of doubles containing coordinate tuples (x, y),i.e. [x0,y0, ..., xN, yN] to an array of half the length containing the same coordinates wrapped in a Point-class, i.e. [p0, ..., pN]?
Preferably .NET 3.5, but also interrested in 4.0.
You can use .Batch from Jon Skeet's morelinq:
IEnumerable<Point> points = coordinates.Batch(2,pair => new Point(pair.ElementAt(0), pair.ElementAt(1)));
In all honestly, the simplest solution is probably using a method (here with ints):
public IEnumerable<Point> GetPoints(int[] coordinates)
{
for (int i = 0; i < coordinates.Length; i += 2)
{
yield return new Point(coordinates[i], coordinates[i + 1]);
}
}
double[] arr = { 1d, 2d, 3d, 4d, 5d, 6d };
var result = arr.Zip(arr.Skip(1), (x, y) => new Point(x, y))
.Where((p, index) => index % 2 == 0);
EDIT: In this LINQ statement, the collection is looped through twice, which is not efficient. A better solution is using a for loop. And Zip is new in C# 4.0, an alternative is:
var result = arr.Select((n, index) => new Point(n, arr[index + 1]))
.Where((p, index) => index % 2 == 0);
This will just loop once and will work in 3.5
int[] arr = new int[] { 1, 1, 2, 2, 3, 3 };
if (arr.Length % 2 != 0)
throw new ArgumentOutOfRangeException();
Point[] result = arr
.Where((p, index) => index % 2 == 0)
.Select((n, index) => new Point(n, arr[index * 2 + 1]))
.ToArray();
And here's another (possibly more "pure") option:
public static class Program
{
public static IEnumerable<Point> ToPoints(this IEnumerable<int> flat)
{
int idx = 0;
while(true)
{
int[] parts = flat.Skip(idx).Take(2).ToArray();
if (parts.Length != 2)
yield break;
idx += 2;
yield return new Point(parts[0], parts[1]);
}
}
static void Main(string[] args)
{
int[] arr = new int[] { 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7 };
var x = arr.ToPoints().ToArray();
return;
}
}
Sure. I haven't compiled /run, so it may have typos, but the gist should be right.
var newArray = source.Aggregate(new List<double>,
(xCoords, next) =>
{
if(xCoords.length % 2 == 0) {
xCoords.Add(next);
}
return xCoords;
},
xCoords => xCoords
).Zip(source.Aggregate(new List<double>,
(yCoords, next) =>
{
if(yCoords.length % 2 != 0) {
yCoords.Add(next);
}
return yCoords;
},
yCoords => yCoords
, (x, y) => new Point(x, y)
).ToArray();

Linq to Objects - return pairs of numbers from list of numbers

var nums = new[]{ 1, 2, 3, 4, 5, 6, 7};
var pairs = /* some linq magic here*/ ;
=>
pairs = { {1, 2}, {3, 4}, {5, 6}, {7, 0} }
The elements of pairs should be either two-element lists, or instances of some anonymous class with two fields, something like new {First = 1, Second = 2}.
None of the default linq methods can do this lazily and with a single scan. Zipping the sequence with itself does 2 scans and grouping is not entirely lazy. Your best bet is to implement it directly:
public static IEnumerable<T[]> Partition<T>(this IEnumerable<T> sequence, int partitionSize) {
Contract.Requires(sequence != null)
Contract.Requires(partitionSize > 0)
var buffer = new T[partitionSize];
var n = 0;
foreach (var item in sequence) {
buffer[n] = item;
n += 1;
if (n == partitionSize) {
yield return buffer;
buffer = new T[partitionSize];
n = 0;
}
}
//partial leftovers
if (n > 0) yield return buffer;
}
Try this:
int i = 0;
var pairs =
nums
.Select(n=>{Index = i++, Number=n})
.GroupBy(n=>n.Index/2)
.Select(g=>{First:g.First().Number, Second:g.Last().Number});
int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7 };
var result = numbers.Zip(numbers.Skip(1).Concat(new int[] { 0 }), (x, y) => new
{
First = x,
Second = y
}).Where((item, index) => index % 2 == 0);
(warning: looks ugly)
var pairs = x.Where((i, val) => i % 2 == 1)
.Zip(
x.Where((i, val) => i % 2 == 0),
(first, second) =>
new
{
First = first,
Second = second
})
.Concat(x.Count() % 2 == 1 ? new[]{
new
{
First = x.Last(),
Second = default(int)
}} : null);
This might be a bit more general than you require - you can set a custom itemsInGroup:
int itemsInGroup = 2;
var pairs = nums.
Select((n, i) => new { GroupNumber = i / itemsInGroup, Number = n }).
GroupBy(n => n.GroupNumber).
Select(g => g.Select(n => n.Number).ToList()).
ToList();
EDIT:
If you want to append zeros (or some other number) in case the last group is of a different size:
int itemsInGroup = 2;
int valueToAppend = 0;
int numberOfItemsToAppend = itemsInGroup - nums.Count() % itemsInGroup;
var pairs = nums.
Concat(Enumerable.Repeat(valueToAppend, numExtraItems)).
Select((n, i) => new { GroupNumber = i / itemsInGroup, Number = n }).
GroupBy(n => n.GroupNumber).
Select(g => g.Select(n => n.Number).ToList()).
ToList();
public static IEnumerable<List<T>> InSetsOf<T>(this IEnumerable<T> source, int max)
{
return InSetsOf(source, max, false, default(T));
}
public static IEnumerable<List<T>> InSetsOf<T>(this IEnumerable<T> source, int max, bool fill, T fillValue)
{
var toReturn = new List<T>(max);
foreach (var item in source)
{
toReturn.Add(item);
if (toReturn.Count == max)
{
yield return toReturn;
toReturn = new List<T>(max);
}
}
if (toReturn.Any())
{
if (fill)
{
toReturn.AddRange(Enumerable.Repeat(fillValue, max-toReturn.Count));
}
yield return toReturn;
}
}
usage:
var pairs = nums.InSetsOf(2, true, 0).ToArray();
IList<int> numbers = new List<int> {1, 2, 3, 4, 5, 6, 7};
var grouped = numbers.GroupBy(num =>
{
if (numbers.IndexOf(num) % 2 == 0)
{
return numbers.IndexOf(num) + 1;
}
return numbers.IndexOf(num);
});
If you need the last pair filled with zero you could just add it before doing the grouping if the listcount is odd.
if (numbers.Count() % 2 == 1)
{
numbers.Add(0);
}
Another approach could be:
var groupedIt = numbers
.Zip(numbers.Skip(1).Concat(new[]{0}), Tuple.Create)
.Where((x,i) => i % 2 == 0);
Or you use MoreLinq that has a lot of useful extensions:
IList<int> numbers = new List<int> {1, 2, 3, 4, 5, 6, 7};
var batched = numbers.Batch(2);
var w =
from ei in nums.Select((e, i) => new { e, i })
group ei.e by ei.i / 2 into g
select new { f = g.First(), s = g.Skip(1).FirstOrDefault() };
var nums = new float[] { 1, 2, 3, 4, 5, 6, 7 };
var enumerable =
Enumerable
.Range(0, nums.Length)
.Where(i => i % 2 == 0)
.Select(i =>
new { F = nums[i], S = i == nums.Length - 1 ? 0 : nums[i + 1] });
Another option is to use the SelectMany LINQ method. This is more for those who wish to iterate through a list of items and for each item return 2 or more of it's properties. No need to loop through the list again for each property, just once.
var list = new [] {//Some list of objects with multiple properties};
//Select as many properties from each Item as required.
IEnumerable<string> flatList = list.SelectMany(i=> new[]{i.NameA,i.NameB,i.NameC});
Another simple solution using index and index + 1.
var nums = Enumerable.Range(1, 10);
var pairs = nums.Select((item, index) =>
new { First = item, Second = nums.ElementAtOrDefault(index + 1) })
.SkipLastN(1);
pairs.ToList().ForEach(p => Console.WriteLine($"({p.First}, {p.Second}) "));
Last item is invalid and must be removed with SkipLastN().
this gives all possible pairs(vb.net):
Dim nums() = {1, 2, 3, 4, 5, 6, 7}
Dim pairs = From a In nums, b In nums Where a <> b Select a, b
Edit:
Dim allpairs = From a In nums, b In nums Where b - a = 1 Select a, b
Dim uniquePairs = From p In allpairs Where p.a Mod 2 <> 0 Select p
note: the last pair is missing, working on it
Edit:
union uniquePairs with the pair {nums.Last,0}

Categories

Resources