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
Related
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
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I have list
List<int> listnumbers
with values { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }.
In some cases i need to add new value for existing values in list example , 0 => 5, 1 => 6 ....
Is there way to do that?
EDIT
i want number to
number 0 have stake 5
number 1 have stake 6
But i cannot that declare on begining of program , only in some cases i woud join stakes
EDIT 2
I will use multidimensional array so it will be
0=>5
1=>6
array[0][0] = 0;
array[0][1] = 5;
array[1][0] = 1;
array[1][1] = 6;
Perhaps this could do what you're looking for. You need some kind of data structure to store the additional information:
public class NumberLink {
int Value { get; set; }
int Link { get; set; }
}
List<NumberLink> numberLinks =
new List<int> {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
}
.Select(i => new NumberLink { Value = i })
.ToList();
numberLinks.First(nl => nl.Value == 0).Link = 5;
numberLinks.First(nl => nl.Value == 1).Link = 6
Please note that if you will always have a range of numbers from 0..n, you don't need this. You can simply use the position of the item in the list to represent the first value, such that a list { 5, 6 } indicates that 0 goes to 5 and 1 goes to 6.
If you need to substitute a value for another, you could use Linq, something along the lines of:
List<int> list = new List<int>(){0,1,2,3,4,5,6};
var fromValue = 0;
var toValue = 7;
list = list.Select( x => x = (x == fromValue ? toValue : x)).ToList();
//- list = {7,1,2,3,4,5,6}
Here the Select statement will mutate your existing list and return a modified list of integers where every value that's equal to fromValue will be replaced with toValue
CASE 1. To add them at the end of the list:
listnumbers.Add(5);
listnumbers.Add(6);
list will be listnumbers ==> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 5, 6 }
CASE 2. To insert them at a specific position:
listnumbers.Insert(0, 5);
listnumbers.Insert(0, 6);
list will be listnumbers ==> { 6, 5, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }
CASE 3. To insert them at position that maintains an ordered list (min to max):
listnumbers.Insert(listnumbers.FindIndex(0, x => x == 5) + 1, 5);
listnumbers.Insert(listnumbers.FindIndex(0, x => x == 6) + 1, 6);
list will be listnumbers ==> { 0, 1, 2, 3, 4, 5, 5, 6, 6, 7, 8, 9, 10, 11, 12 } and in this case, I am using predicates within FindIndex method.
I am guessing that you want to add some constant value to each element of a list and return it as a new list.
List<int> answer = listnumbers.Select(x => x+valueToBeAdded).ToList();
The above statement adds a constant to all elements of the list and returns it as a new list.
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();
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);
I have a list of integers that I would like to search for a sequence.
For example, if I have a master list:
1, 2, 3, 4, 9, 2, 39, 482, 19283, 19, 23, 1, 29
And I want to find sequence:
1, 2, 3, 4
I would like some easy way to fill a subset list with:
1, 2, 3, 4 + the next five integers in the master list
And then remove the integers in the subset list from the master list so at the end of the operation, my lists would look like this:
Master list:
19, 23, 1, 29
Subset list:
1, 2, 3, 4, 9, 2, 39, 482, 19283
Hope that makes sense. I'm guessing maybe LINQ would be good for something like this, but I've never used it before. Can anyone help?
You could start with writing a function IndexOfSublist that can find a sublist inside a list. This has been asked many times before.
Assuming you have implemented IndexOfSublist, use it to find the first element of your result, then you could use GetRange to select the elements that you want to keep and then RemoveRange to remove the elements from the original list.
List<int> l = new List<int> { 1, 1, 2, 3, 4, 9, 2, 39, 482, 19283, 19, 23, 1, 29 };
List<int> needle = new List<int> { 1, 2, 3, 4 };
int i = indexOfSubList(l, needle);
if (i != -1)
{
// TODO: What should we do if there are fewer than four
// elements left after the needle? Currently we just throw.
List<int> result = l.GetRange(i, needle.Count + 4);
l.RemoveRange(i, result.Count);
// TODO: Do something with the result;
}
HINT
you can try something like this along with an iterator:
List<int> n = new List<int>() { 1, 2, 3, 4, 9, 2, 39, 482, 19283, 19, 23, 1, 29 };
List<int> toFind = new List<int>() { 1, 2, 3, 4 };
if (n.Skip(indextostart).Take(4).ToList()==toFind)
{
n.RemoveRange(indextostart,4);
}