Given two arrays, I need to extract values from arrayB based on where the range(actual values) falls in arrayA.
Index 0 1 2 3 4 5 6 7 8 9 10 11 12
-------------------------------------------------------------
ArrayA = {0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6}
ArrayB = {1, 0.2, 3, 4, 5, 6,5.5, 8, 9,11.1, 11, 12, 3}
Given the following ranges, I need to extract the following results
RangeToExtract* IndexInArrayA Expected Values To Extract
-------------- ------------- --------------------------
0 -> 1 [0,2] 1,0.2,3
1 -> 3 [3,6] 4,5,6,5.5
3 -> 5 [7,10] 5.5,8,9,11.1,11
1 -> 5 [3,10] 4,5,6,5.5,8,9,11.1,11
3 -> 10 [7,12] 8,9,11.1,11,12,3
* Refers to the actual values in ArrayA
Note: Given the RangeToExtract (0->1), determine the indexes in ArrayA where these values are, the result being (0->1) maps to [0,2] (The value 1 is in position 2 in ArrayA)
I only figured that the following special cases exists (not sure if there are more)
the lower limit is equal to zero and
when the upper limit does not exist in ArrayA
Further info:
Both arrays will be the same size
ArrayA will always be sorted
Code:
private double[] GetRange(double lower, double upper)
{
var myList = new double[ArrayA.Length];
var lowerIndex = Array.IndexOf(ArrayA, lower);
var upperIndex = Array.IndexOf(ArrayA, upper);
// special case 1
if (lowerIndex != 0)
{
lowerIndex = lowerIndex + 1;
}
// special case 2
if (upperIndex == -1)
{
upperIndex = ArrayA.Length-1;
}
for (int i = lowerIndex; i <= upperIndex; i++)
{
myList[i] = ArrayB[i];
}
return myList;
}
Given the above code, have all the special cases been taken into account? Is there a better way to write the above code?
Yap! There is a quite better way, that comes with lovely LINQ. I put here in two forms. First looks complicated but not at ALL! Believe me ;)
At the first step you have to take out those A'indexes that their values fall into your range (I call it min...max), based on your example I got that your range is closed from the lower boundary and closed on upper side, I means when you mentioned 3 -> 5 actually It is [3, 5)! It does not contain 5. Anyway that is not the matter.
This can be done by following LINQ
int[] selectedIndexes = a.Select((value, index) =>
new { Value = value, Index = index }).
Where(aToken => aToken.Value > min && aToken.Value <= max).
Select(t => t.Index).ToArray<int>();
The first select, generates a collection of [Value, Index] pairs that the first one is the array element and the second one is the index of the element within the array. I think this is the main trick for your question. So It provides you with this ability to work with the indexes same as usual values.
Finally in the second Select I just wrap whole indexes into an integer array. Hence after this you have the whole indexes that their value fall in the given range.
Now second step!
When you got those indexes, you have to select whole elements within the B under the selected Indexes from the A. The same thing should be done over the B. It means again we select B element into a collection of [Value, Index] pairs and then we select those guys that their indexes exist within the selected indexes from the A. This can be done as follow:
double[] selectedValues = b.Select((item, index) =>
new { Item = item, Index = index }).
Where(bToken => selectedIndexes.Contains(bToken.Index)).
Select(d => d.Item).ToArray<double>();
Ok, so first select is the one I talked about it in the fist part and then look at the where section that check whether the index of the bToken which is an element of B exists in the selectedIndexes (from A) or not!
Finally I wrap both codes into one as below:
double[] answers = b.Select((item, index) =>
new { Item = item, Index = index }).
Where(bTokent =>
a.Select((value, index) =>
new { Value = value, Index = index }).
Where(aToken => aToken.Value > min && aToken.Value <= max).
Select(t => t.Index).
Contains(bTokent.Index)).Select(d => d.Item).ToArray<double>();
Buy a beer for me, if it would be useful :)
I don't know if you're still interested, but I saw this one and I liked the challenge. If you use .Net 4 (having the Enumberable.Zip method) there is a very concise way to do this (given the conditions under futher info):
arrayA.Zip(arrayB, (a,b) => new {a,b})
.Where(x => x.a > lower && x.a < upper)
.Select (x => x.b)
You may want to use >= and <= to make the range comparisons inclusive.
Related
I have been working through the daily coding problems and came to this one.
Given an array of integers, return a new array such that each element
at index i of the new array is the product of all the numbers in the
original array except the one at i.
For example, if our input was [1, 2, 3, 4, 5], the expected output
would be [120, 60, 40, 30, 24]. If our input was [3, 2, 1], the
expected output would be [2, 3, 6].
Follow-up: what if you can't use division?
So the easy way to do this would be just to multiply all the elements in the array and then just divide by [i] but that gives the problem that if I = 0 you are going to get an exception error.
I'm aware of the aggregate function that does an operation on all members of an array but is there a way to modify aggregate so that it does it to all members but one, or is there some other function/method that gives this functionality?
If source is small, you can skip index with a help of Where, e.g.
int[] source = new int[] { 1, 2, 3, 4, 5 };
int[] result = Enumerable
.Range(0, source.Length)
.Select(i => source
.Where((value, index) => index != i) // all items except i-th
.Aggregate((s, a) => s * a)) // should be multiplied
.ToArray();
Console.Write(string.Join(", ", result));
Outcome:
120, 60, 40, 30, 24
Edit: However, the solution has O(N**2) time complexity; in case the initial source array is large we can implement a more efficient O(N) code (and yes, we should mind zeroes):
int[] source = ...
int[] result;
int zeroCount = source.Count(item => item == 0);
if (zeroCount >= 2) // All zeroes case
result = new int[source.Length];
else if (zeroCount == 1) // All zeroes save one value case
result = source
.Select(v => v == 0
? source.Where(item => item != 0).Aggregate((s, a) => s * a)
: 0)
.ToArray();
else { // No zeroes case
// long, 1L: to prevent integer overflow, e.g. for {1000000, 1000000} input
long total = source.Aggregate(1L, (s, a) => s * a);
result = source
.Select(v => (int)(total / v)) // yes, it's a division...
.ToArray();
}
There are no built-in functions that aggregate on all except a single specified member (would you specify it by value or by index?)
However, a loop would be very straightforward, and Linq gives you the Where method where you can create whatever predicate you want and can then apply aggregations on the filtered result.
So to sum all numbers of an array instead of the third one, for example, you could do something like:
array.Where((x,i) => i != 2).Sum(); // use 2 since the index is 0-based
There's also not a built-in Linq method for Product, but I'm certain there's one out there, or again you could easily roll-your-own.
I have a list of strings, which contains information, which I want to save in separate variables.
The .txt file contains line with this kind of information:
1 kitchen 1 microwave microwave2 relevant 0.0025 1.29 0.88 1.29
var index = Enumerable.Range(2, 3).ToArray();
string objectInformationText = System.IO.File.ReadAllText("objectList.txt");
string[] objectInformation = objectInformationText.Split('\t');
Now, I want to extract items from objectInformation based on my index (i.e. item 2 and 3). The output should be a subset only containing items 2 and 3 from the list.
A solution can be using lambda Select function as follow:
var result = index.Select(x => information[x]).ToList();
While #OmG's answer is correct, the alternative for creating a temp collection of indexes in your case would be using Skip/Take linq selectors.
objectInformation.Skip(2).Take(3)
This will obviously work only for contiguous span of indexes.
In linQ there is a lot of way to select based on the index.
string input = "1 kitchen 1 microwave microwave2 relevant 0.0025 1.29 0.88 1.29";
var spt = input.Split(' ');
//Select everything after the 1 element:
var afterTitle = spt.Skip(1);
//Select from index 2 to 5 incuding them -> 1 microwave microwave2 relevant
var from2to5 = spt .Skip(2) // Skip index 0, 1
.Take(4); // Take 2,3,4,5
//Select based on a Index list, OmG's answer is a better alternative for this one.
int[] idx = { 1, 2, 4, 5 };
var inIdx = spt.Where((value,index)=> idx.Contains(index));
The last exemple will be usefull when the index needed could be calculated.
//Select only the Even one
var even = spt.Where((value,index)=> index%2==0);
I was doing some work by my own for upcoming test and found this question that I could not understand.
int[] div = new int[]{2,3,5};
IEnumerable<int>seq = new int[]{10,15,20,25,30};
for(int i = 0; i<div.Length;i++){
int y = div[i];
seq = seq.Where(s => s%y == 0)
}
seq = seq.ToList();
I thought the resulting sequence would be 10 15 20 25 30 but the actual answer was 30.
I tried to run the code by my self and I found that when the code runs the for-loop, the sequence does not resets to the original but it keeps the sequence created by the previous div[i].
For example, when i = 0, div[0] is 2 so the seq picks the 10, 20 and 30.
As the code proceeds to i = 1 and div[1] = 3, the sequence it uses for the calculation part is still {10,20,30} not {10,15,20,25,30}.
Can someone explain why?
When I move int y to the outside of the for-loop like this,
int[] div = new int[]{2,3,5};
IEnumerable<int>seq = new int[]{10,15,20,25,30};
int y;
for(int i = 0; i<div.Length;i++){
y = div[i];
seq = seq.Where(s => s%y == 0)
}
seq = seq.ToList();
it gives the answer I was expecting.
Any help will be really helpful.
Thank you.
This is the resulting query you end up with:
IEnumerable<int> seq = new int[]{10,15,20,25,30};
seq = seq
.Where(s => s%2 == 0)
.Where(s => s%3 == 0)
.Where(s => s%5 == 0);
So, every number that is divisible by 2, 3 and 5:
10 is not divisible by 3
15 is not divisible by 2
20 is not divisible by 3
25 is not divisible by 2
30 is divisible by 2 (15), 3 (10), and 5 (6)
So 30 is the only result.
Now, if you instead want this query: "I want every number in seq that is divisible by 2, 3 or 5", then you need to do it different.
The code you had will filter every step of the way, only letting through to the next step any numbers that fit, so each will filter, but you want the opposite, if any one of them would say that it was OK, then you want the number.
To get the or expression instead, this would be the code:
seq.Where(s => div.Any(y => s % y == 0))
This gives this result:
10
15
20
25
30
Basically this query says:
Any number s in seq, which for any number y in div, where s is divisible by y.
As for your last part, why did it change after you moved the y outside the loop?
Well, let's see what actually happens.
When you have the y inside the loop, as in the first example, for each iteration through the loop, you can think of y as a "new y just for this loop iteration".
As such, you can think of the code that is being executed producing this query:
int y1 = 2;
int y2 = 3;
int y3 = 5;
seq = seq
.Where(s => s%y1 == 0)
.Where(s => s%y2 == 0)
.Where(s => s%y3 == 0);
But, if you move the y variable outside the loop you only ever have one y, which you change, so the final result is this:
int y = 5; // the last number in the loop
seq = seq
.Where(s => s%y == 0)
.Where(s => s%y == 0)
.Where(s => s%y == 0);
Which basically checks that every number is divisible by 5, 3 times.
So while you say that this gives you the result you want, it doesn't do what you want. Or rather, I assume it doesn't do what you want since you haven't actually described what you wanted the code to do.
Here are some links that explain the differences:
Anonymous Methods (MSDN)
Captured variable in a loop in C#
Detailed Explanation of Variable Capture in Closures
You code can be simplified by adding some more LINQness.
If what you are trying to get is the values of seq that can be divided by any of the values of div, you can simply do:
seq.Where(s => div.Any(d => s%d == 0));
If you want the values of seq that can be divided by all of the values of div, replace the .Any with .All.
Panagiotis Kanavos introduced the following clever solution to produce LetterNumberNumber pattern in this SOF question: For loop when the values of the loop variable is a string of the pattern LetterNumberNumber?
var maxLetters=3; // Take 26 for all letters
var maxNumbers=3; // Take 99 for all the required numbers
var values=from char c in Enumerable.Range('A',maxLetters).Select(c=>(char)c)
from int i in Enumerable.Range(1,maxNumbers)
select String.Format("{0}{1:d2}",(char)c,i);
foreach(var value in values)
{
Console.WriteLine(value);
}
A01
A02
A03
B01
B02
B03
C01
C02
C03
D01
D02
D03
Is there way to instruct irregular course in Enumerable stuff? "Enumerable.Range(1, maxNumbers)" leads 01, 02, ...,99 (for maxNumbers 99).
Restriction Examples:
1. Restrict (01,02,...,99) only to (01,03,05,07,09,11,13)
2. Restrict (01,02,...,99) only to (02,04,06,08,10)
3. Restrict (01,02,...,99) only to (01,04,09,10)
What I did:
I worked "Enumarable", tried its methods like: Enumerable.Contains(1,3,5,7,9,13) gave big error, and I could not achieve to reach:
A01, A03, A05, ....,Z09, Z11, Z13.
If Enumarable is not suitable for this type of job, what do you offer to handle the problem?
This isn't a direct feature in C#, while it is in F#.
F# example:
[1..2..10]
will produce a list of [1,3,5,7,9].
You first example, "Restrict (01,02,...,99) only to (01,03,05,07,09,11,13)" can be achieved with
Enumerable.Range(1,99).Where(x => x % 2 == 1).Take(7);
The second example, "Restrict (01,02,...,99) only to (02,04,06,08,10)" can be achieved with
Enumerable.Range(1,99).Where(x => x % 2 == 0).Take(5);
And your third example, "Restrict (01,02,...,99) only to (01,04,09,10)" seems odd. I'm not sure what the pattern here is. If the last element isn't a typo, then starting at one and incrementing by 3, then 5, then 1 seems unclear, but here's a method that can accomplish it.
public static IEnumerable<int> GetOddMutation(int start, int max, int count, List<int> increments) {
int counter = 0;
int reset = increments.Count - 1;
int index = 0;
int incremented = start;
while(counter < count) {
var previous = incremented;
incremented += increments[index];
index = index == reset ? 0 : index + 1;
counter++;
if(previous != incremented) //Avoid duplicates if 0 is part of the incrementation strategy. Alternatively, call .Distinct() on the method.
yield return incremented;
}
}
called with
GetOddMutation(1,99,4, new List<int> {0,3,5,1})
will result in [1,4,9,10]
It sounds to me like you want the Enumerable.Range(1, maxNumbers) to be restricted by a certain condition rather than having all of the integers. Since Enumerable.Range() produces an IEnumerable<int>, you can chain any LINQ filtering method calls, namely the Enumerable.Where() method. For example, Enumerable.Range(1, 99).Where(x => x % 3 == 0) would yield (3,6,9,...99).
If you only wanted the specific case you specified where the list only contains (1,3,5,7,9,13), you could simply make a list with the desired numbers: new List<int> {1,3,5,7,9,13}; you could also use Enumerable.Range(1, maxNumbers).Where(x => x % 2 == 1) and maxNumbers = 13.
I have a DataSet that contains a column, call it Type which contains ints. I'm using LINQ to manipulate the DataSet and I want to sort by Type. The Type column only contains 3 values right now (1, 2, 3). I would like to sort so that Type 2 are first in the list and then 1 and 3.
Is there an easy solution for this or am I going to have to customize the OrderBy?
Few solutions :
table.AsEnumerable()
.OrderBy(r => r.Field<int>("Type")==2 ? 0 : 1)
.ThenBy(r => r.Field<int>("Type"));
or probably better
table.AsEnumerable().
OrderBy(r => r.Field<int>("Type")==2
? 0
: r => r.Field<int>("Type"))
or also elegant Tim Schmelter's solution
table.AsEnumerable()
.OrderByDescending(r => r.Field<int>("Type")==2)
.ThenBy(r => r.Field<int>("Type"))
Advantage or Tim Schmelter's solution : you're not depending on a "pseudo-value".
In the two first solutions, we assert that 0 is ((min possible value of the field) -1).
Is this real, can it change, we don't know.
To make the sample simpler I removed the fact that we start from a DataTable, it's just a detail, and I thought we could do this:
var list = new [] { 1, 3, 5, 2, 4, 6, 9, 8 };
var sorters = new [] { 3, 2, -1 };
var o = from s in sorters
from l in list.OrderBy(x => x)
where s == l || (s == -1 && !sorters.Contains(l))
select l;
The sort array contains the preferred sorters, this way we can have more than one if we need them, and then there is a 'jolly' (-1) to represent the end of the sorters. The jolly could be handled in a better way, it's like that just to give you the idea. At this point the algorithm is generic and does not need any hard-coded check on the preferred values (just the jolly).
There are some potential inefficiencies, but I just wanted to show the general idea of this solution, with some more works it could be done more efficiently.
Here you have like 5 ways of accomplishing this. It's a post regarding how to set value as the first of the order, then throw in the ones lower, and after the ones higher than the selected so if you have {1 2 3 4 5 6} and select item 4, output: {4 1 2 3 5 6}.. I prefer my own answer though.. ^_^
https://stackoverflow.com/a/12580121/920359