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);
nik
  • 1,672
  • 2
  • 17
  • 36
  • 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! – Konrad Viltersten Feb 14 '16 at 09:53
  • For instance, why is the *expiry* array composed of exactly 18 elements? – Konrad Viltersten Feb 14 '16 at 09:54
  • what about this ? http://stackoverflow.com/questions/943635/getting-a-sub-array-from-an-existing-array – Bob T. Feb 14 '16 at 09: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 – nik Feb 14 '16 at 09:56
  • Are you trying to pick all the elements of *expiry* that match a condition comparing to *values*? – Konrad Viltersten Feb 14 '16 at 09:58
  • @BobT.: yes, but this works only with start and end index but my elements could be all over the place. I could however sort one array based on the other, determine the start and end index and then use the method in that answer – nik Feb 14 '16 at 09:59
  • @KonradViltersten: yes – nik Feb 14 '16 at 09:59
  • If items in `expiry` and `values` are related (by index), why not have a small struct/class that holds them together, so you only have *one* array? Then you could just say `var filteredArray = itemArray.Where(item => item.Expiry == 0.75).ToArray();` – Corak Feb 14 '16 at 10:02
  • I would accept one of the answers (@RossPresser has a great one), ask a new question and explain a bit more what the code's supposed to do, if I were you. – Konrad Viltersten Feb 14 '16 at 10:20

3 Answers3

5

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

double[] newVals = values.Where((t, i) => expiry[i] == 0.75).ToArray();
Ross Presser
  • 6,027
  • 1
  • 34
  • 66
aminexplo
  • 360
  • 1
  • 13
  • 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. – Ross Presser Feb 14 '16 at 10:12
  • 1
    @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. – Konrad Viltersten Feb 14 '16 at 10:14
  • @RossPresser: great thank you. I cant see any difference between your two answers though. Am I missing sth please? – nik Feb 14 '16 at 10:24
  • @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. – Ross Presser Feb 14 '16 at 10:25
  • It was still adding information that had already been there for five minutes, in near identical form - but this time with less context. – Pekka Feb 14 '16 at 10:33
  • @aminexplo I'm not saying that you did steal the content. I'm just pointing out that it sure appears like that. Wouldn't you agree...? – Konrad Viltersten Feb 14 '16 at 10:39
  • @Pekka웃 Perhaps I'm missing it but I can't see the **addition** of the information. I only see a down-stripping of some rows and parenthesis... Please correct me if I'm missing something. I do want to believe in the good of people, hehe. – Konrad Viltersten Feb 14 '16 at 10:41
  • I took well over four minutes to compose my own answer while experimenting in LINQPad; and then after I hit Submit I realized Konrad had given an answer. Wouldn't surprise me to hear aminexplo did the same. – Ross Presser Feb 14 '16 at 10:45
  • @KonradViltersten Absolutely not... Maybe what you are thinking about me, has happened a couple of times for yourself.. ha ha... that's why this situation(other submits during compose) appears so wierd to you... – aminexplo Feb 14 '16 at 10:59
  • @aminexplo Yes, it's happened to me a few times, like you say. I don't understand why people copy off my answer and post it as their own... Anyway, it **does** look like a shorter version of someone else's answer **but** posted a few minutes later. It's not a *proof*, of course, but the patter does suggest the likelihood of plagiarism. It's definitely not a counter-proof, for sure. Anyway, it's not really worth our time to dwell on it, right? – Konrad Viltersten Feb 14 '16 at 11:05
  • @Konrad I meant to say, this answer adds nothing of value that wasn't already there. – Pekka Feb 14 '16 at 11:14
  • @KonradViltersten Oh sure... have fun with your cynical hypothesis. The truth was what i explained :). – aminexplo Feb 14 '16 at 11:22
  • @aminexplo You do realize that the more you deny it, the more obvious it becomes, don't you? I pointed out that the **pattern suggests the likelihood of plagiarism**. And it does, you can't deny that. I'm not stating for sure that you stole the reply. I just say that (as others pointed out) your answers adds nothing to the discussion **and** that it was posted a few minutes after the original answer. Those are the undeniable facts. I have no intention to keep debating the interpretations, though. Those are subjective. – Konrad Viltersten Feb 14 '16 at 11:25
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();
Konrad Viltersten
  • 36,151
  • 76
  • 250
  • 438
Ross Presser
  • 6,027
  • 1
  • 34
  • 66
  • 1
    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. – Konrad Viltersten Feb 14 '16 at 10:16
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.

Community
  • 1
  • 1
Konrad Viltersten
  • 36,151
  • 76
  • 250
  • 438
  • You know, I didn't know about `Zip`. I [see](https://msdn.microsoft.com/library/dd267698(v=vs.100).aspx) that it's new in .NET 4. Interesting, I probably can find somewhere it should be used in my code :) – Ross Presser Feb 14 '16 at 11:42
  • 1
    @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... – Konrad Viltersten Feb 14 '16 at 11:53