How to split array in two arrays? - c#

I have one array and want split it in to two:
Now: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
New_1: [0, 2, 4, 6, 8]
New_2: [1, 3, 5, 7, 9]
So take the one element and skip the next element.
Look easy but how can i do it with C#?
Thanks a lot

You can use linq, Enumerable.Where and get the array with elements that have even and odd indexes.
var New_1 = arr.Where((c,i) => i % 2 == 0).ToArray();
var New_2 = arr.Where((c,i) => i % 2 != 0).ToArray();
You can get the index of element of collection and apply condition to check if index is even or odd and get the arrays according.
Enumerable.Where Method (IEnumerable, Func) filters a sequence of values based on a predicate.
Each element's index is used in the logic of the predicate function.
The first argument of predicate represents the element to test. The
second argument represents the zero-based index of the element within
source, msdn

How about something like
int[] arr = new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int[] arr1 = arr.Where((x, i) => i % 2 == 0).ToArray();
int[] arr2 = arr.Where((x, i) => i % 2 == 1).ToArray();

int[] arr = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int i = 0;
List<int[]> twoArr = arr.GroupBy(x => i++ % 2).Select(g => g.ToArray()).ToList();

Related

Performing Actions With Pairs in Arrays/Lists in C#

Sorry if the title's worded a bit weird but this is what I'm trying to get to.
Lets say you have an array of integers like this:
int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
What would be the best way to use this array to return a new array but with the values of each pair summed together, so using the array above, it would return
{ 3, 7, 11, 15, 19 }
Obviously you can so something basic like
int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var x = new List<int>();
for (int i=0;i<arr.Length;i+=2)
x.Add(arr[i] + arr[i+1]);
But if you want to keep your code concise and/or work with different items, this doesn't really seem like the best option.
So is there any other/better way to do this? I was testing some ideas with Enumerable.Aggregate but couldn't come up with anything, please share ideas.
I would argue that your approach is perfectly fine, but for LINQ you can do some stuff with Chunk:
var x = arr
.Chunk(2)
.Where(c => c.Length == 2)
.Select(c => c.Sum())
.ToArray();
Well, your code is readable and efficien; however, you can generalize your current solution a bit:
Last array item(s) can well have no pair
We can combine not only pairs, but three or four items etc.
If you are looking for such kind of code for
int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
the modifiction of your solution can be:
const int size = 2;
int[] result = new int[arr.Length / size + Math.Sign(arr.Length % size)];
for (int i = 0; i < arr.Length; ++i)
result[i / size] += arr[i];
For instance, if we set size = 3; then for we'll get { 6, 15, 24, 10 } as the result. Note, that the last group is incomplete:
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
| | | | | | ||
6 15 24 10

How to convert a sequence of points to a sequence of ranges?

For example, I have a sequence of points
List points = new List {0, 1, 2, 4, 5 ,7};
And I want to convert it to a sequence of ranges (My type Range(leftPoint, rightPoint)). For the example, results are
List<Range> ranges: {0, 1} {1, 2} {2, 4} {4, 5} {5, 7}
You could use LINQ (presuming the list is already sorted):
List<Range> rangeList = Enumerable.Range(0, points.Count - 1)
.Select(i => new Range(points[i], points[i + 1]))
.ToList();
Why not just use a simple for-loop?
for(var i = 0; i < points.Count() - 1; i++)
ranges.Add(new Range(points[i], points[i+1]))
List<int> points = new List<int> { 0, 1, 2, 4, 5, 7 };
List<List<int>> listOfRanges = new List<List<int>>();
listOfRanges.Add(points.GetRange(0, 2));
listOfRanges.Add(points.GetRange(1, 2));
listOfRanges.Add(points.GetRange(2, 2));
listOfRanges.Add(points.GetRange(3, 2));
listOfRanges.Add(points.GetRange(4, 2));
You can iterate over it like so:
List<int> points = new List {0, 1, 2, 4, 5 ,7};
List<Range> listOfRanges = new List<Range>();
int index = 0
foreach (int value in points) {
listOfRanges.add(new Range(points[i], points[i+1]));
index++;
}
You might get a null comparison exception on the last iteration of the loop as points[i+1] doesn't exist - if so just handle this with a simple if statement.
This is assuming by points you mean a list of integers. I'll update if I find you meant something different.
You can use LINQ to zip the two lists that we get when we:
Take everything except the last element
Take everything except the first element
These correspond to (in the case of your example):
0, 1, 2, 4, 5
1, 2, 4, 5 ,7
Here is how you do it in code:
var result =
points
.Take(points.Count - 1) //points except last element
.Zip(
points.Skip(1), //points except first element
(l, r) => new Range(l, r))
.ToList();

How to find first specific item and then take 3 following?

I am trying to find position in a List based on where LINQ statement and get that item and next (x) amount. Example code:
List<int> numbers = new List<int>(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
numbers = numbers.Where(elt => elt == 6).Take(3).ToList();
I am trying to get back a filtered list of 6,7,8. However this is not working. Am I approaching this wrong?
Thanks in advance!
You almost got it. You just need to change the Where to a SkipWhile:
numbers = numbers.SkipWhile(elt => elt != 6).Take(3).ToList();
You have to use Where() overload that takes index of item as well and then use with indexOf():
List<int> numbers = new List<int>(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
var result = numbers.Where((x, i) => i >= numbers.IndexOf(6)).Take(3);
Here's another approach which comes into play when it's possible that the number is not unique and you want all occurences including the two next followers:
List<int> numbers = new List<int>(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 6, 7, 8, 9, 6 });
numbers = Enumerable.Range(0, numbers.Count)
.Where(index => numbers[index] == 6)
.SelectMany(index => numbers.Skip(index).Take(3))
.ToList(); // 6,7,8,6,7,8,6

Lambda expressions: index of an element in the array

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
int oddNumbers = numbers.Count(n => n % 2 == 1);
var firstNumbersLessThan6 = numbers.TakeWhile(n => n < 6);
var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);
These are C# code taken from http://msdn.microsoft.com/en-us/library/bb397687.aspx
I understand the first two lambda expressions just fine by considering n as an element of the array "numbers".
However the third lambda expression is really confusing with "index". Is (n,index) one of the lambda parameters well established for arrays? Is this a convention?
When TakeWhile iterates over the collection:
n is the value of the element
index is the index of the element
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
// As TakeWhile iterates over the array:
// "n" is the value of the element
// "index" is the index of the element
var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);
foreach(var n in firstSmallNumbers)
Console.WriteLine(n);
Output:
5 4
Run this at: https://dotnetfiddle.net/4NXRkg

Linq query that reduces a subset of duplicates to a single value within a larger set?

Is there a linq command that will filter out duplicates that appear in a sequence?
Example with '4':
Original { 1 2 3 4 4 4 5 6 7 4 4 4 8 9 4 4 4 }
Filtered { 1 2 3 4 5 6 7 4 8 9 4 }
Thanks.
Not really. I'd write this:
public static IEnumerable<T> RemoveDuplicates(this IEnumerable<T> sequence)
{
bool init = false;
T current = default(T);
foreach (var x in sequence)
{
if (!init || !object.Equals(current, x))
yield return x;
current = x;
init = true;
}
}
Yes there is! One-line code and one loop of the array.
int[] source = new int[] { 1, 2, 3, 4, 4, 4, 5, 6, 7, 4, 4, 4, 8, 9, 4, 4, 4 };
var result = source.Where((item, index) => index + 1 == source.Length
|| item != source[index + 1]);
And according to #Hogan's advice, it can be better:
var result = source.Where((item, index) => index == 0
|| item != source[index - 1]);
More readable now i think. It means "choose the first element, and those which isn't equal to the previous one".
Similar to svick's answer, except with side effects to avoid the cons and reverse:
int[] source = new int[] { 1, 2, 3, 4, 4, 4, 5, 6, 7, 4, 4, 4, 8, 9, 4, 4, 4 };
List<int> result = new List<int> { source.First() };
source.Aggregate((acc, c) =>
{
if (acc != c)
result.Add(c);
return c;
});
Edit: No longer needs the source.First() as per mquander's concern:
int[] source = new int[] { 1, 2, 3, 4, 4, 4, 5, 6, 7, 4, 4, 4, 8, 9, 4, 4, 4 };
List<int> result = new List<int>();
result.Add(
source.Aggregate((acc, c) =>
{
if (acc != c)
result.Add(acc);
return c;
})
);
I think I still like Danny's solution the most.
You can use Aggregate() (although I'm not sure whether it's better than the non-LINQ solution):
var ints = new[] { 1, 2, 3, 4, 4, 4, 5, 6, 7, 4, 4, 4, 8, 9, 4, 4, 4 };
var result = ints.Aggregate(
Enumerable.Empty<int>(),
(list, i) =>
list.Any() && list.First() == i
? list
: new[] { i }.Concat(list)).Reverse();
I think it's O(n), but I'm not completely sure.
If you're using .NET 4 then you can do this using the built-in Zip method, although I'd probably prefer to use a custom extension method like the one shown in mquander's answer.
// replace "new int[1]" below with "new T[1]" depending on the type of element
var filtered = original.Zip(new int[1].Concat(original),
(l, r) => new { L = l, R = r })
.Where((x, i) => (i == 0) || !object.Equals(x.L, x.R))
.Select(x => x.L);

Categories

Resources