2

There are a bunch of answers on how to get a subarray with start and end index or start index and length. But I m looking for a way to get an subarray based on index array. Here is what I have (which works fine but seems clunky).

//sample arrays (could be unordered)
double[] expiry= { 0.99, 0.9, 0.75, 0.60, 0.5, 0.4, ...};
double[] values = { 0.245, 0.24, 0.235, 0.22, 0.21, 0.20, ... };


//find index of all elements meeting criteria in array expiry
int[] expind = expiry
  .Select((b, i) => b == 0.75? i : -1)
  .Where(i => i != -1).ToArray();

//create new arrays of appropriate size
double[] newvalues = new double[expind.Length];

//populate new arrays based on index
for (int i = 0; i < expind.Length; i++)
  newvalues[i] = values[expind[i]];

//check values
foreach (var item in newvalues)
   Console.WriteLine(item);

Is there a more efficient and general way of doing this please?

UPDATE

next attempt (Still not super efficient, but at least loopless):

Array.Sort(expiry, values);     
double criteria = 0.75;
int start = Array.IndexOf(expiry, criteria);
int last = Array.LastIndexOf(expiry, criteria);
int length = last - start + 1;
double[] newvalues2 = new double[length];
Array.Copy(values, start, newvalues2, 0, length);
9
  • 1
    Could you explain in a few words what's supposed to happen in the loops? As you said, it's a bit clunky and as a lazy reader, I prefer to read English instead of C#ish, hehe. Kudos for wanting to write it neater! Commented Feb 14, 2016 at 9:53
  • For instance, why is the expiry array composed of exactly 18 elements? Commented Feb 14, 2016 at 9:54
  • what about this ? stackoverflow.com/questions/943635/… Commented Feb 14, 2016 at 9:55
  • sorry, made it more legible. Point is, I have two arrays, I filted on one to get an index and then apply this index to the second to create subarray Commented Feb 14, 2016 at 9:56
  • Are you trying to pick all the elements of expiry that match a condition comparing to values? Commented Feb 14, 2016 at 9:58

3 Answers 3

5

Hi you can find the values in this way using lambda expression:

double[] newVals = values.Where((t, i) => expiry[i] == 0.75).ToArray();
Sign up to request clarification or add additional context in comments.

13 Comments

I disagree, Konrad. This answer, and mine, use the Where((t,i) =>...) LINQ form, using the index to compare an element in expiry but collecting matching results from values at the same index point.
@RossPresser I stand corrected. I missed that he had two different references there. You are right. It seems he just copied a part of your answer and that confused me.
@RossPresser: great thank you. I cant see any difference between your two answers though. Am I missing sth please?
@nik: No difference. This answer is the same as the (first part) of my answer. The second part of my answer (after I edited it) gives a solution when you have the array of indices already, instead of the source array it came from.
It was still adding information that had already been there for five minutes, in near identical form - but this time with less context.
|
3

This is a bit more concise. no need to actually put the indexes into an expind array; just use the indices directly with the Where() overload that takes an index:

double[] newpoints = points.Where((p, i) => (expiry[i] == 0.75)).ToArray();
double[] newvalues = values.Where((v, i) => (expiry[i] == 0.75)).ToArray();

See deeper discussion.

Now, if for some reason you already have an array of expind indices, but not the original array of expiry it came from, you can do this:

double[] newpoints = expind.Select(ind => values[ind]).ToArray();

1 Comment

In fact, this is the shortest solution to OP's question. Mine's more elaborative and assumes that he's going to do more stuff later on. But I already +1'ed you for the sharpness and to-the-pointness.
2

Depending on the circumstances, this might work for you.

private static IEnumerable<double> GetByCondition(List<double> expiry, List<double> value)
{
  for(int i = 0; i < expiry.Count; i++)
    if(expiry[i] == 0.75)
      yield return value[i];
}

Furthermore, I'd put it as a extension method, if frequently used in your arrays/lists.

public static IEnumerable<double> GetValuesByExpiry(
  this List<double> self, List<double> values)
{
  return GetByCondition(self, values);
}

As @Corak mentioned, the problem might be eliminated all together if you merge those two arrays into a single one consisting of touples. If appropriate in your case, of course. You can probably zip them together.

2 Comments

You know, I didn't know about Zip. I see that it's new in .NET 4. Interesting, I probably can find somewhere it should be used in my code :)
@RossPresser Oh, happy to be of help. I'm using it pretty often on one of my jobs because everything there (and I mean everything) comes in by arrays of separate lists, while actually being coupled data. An incompetent design a while back makes it impossible to change the format of delivered information. So the first step is to transform it. Then, the work's easy. Also, pfewww... What an infected discussion of all that... I'll think twice before doing it again. Shutthehellupness skills would be beneficial here...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.