-1

I have the following class

public class DataStore
{
   public int index {get;set;}
   public string value {get;set;}
}

I then have a list like this:

var dataStoreList = new List<DataStore> 
{ 
    //Initialise with lots of objects 
}

I now want to populate the index value with the items index in the List.

I know I can use a for loop, but is there a one liner I can use to do this? Maybe linq has a function? I have googled a few terms but have not found anything that helps yet

Alex
  • 3,730
  • 9
  • 43
  • 94
  • 1
    Create an extension method for List and call that. Or better still create and extension method for List and pass a selector to access the index property. – Whelkaholism May 01 '19 at 14:42
  • Is the `value` already populated in this list, or are you wanting to populate that also? – Brian Rogers May 01 '19 at 14:43
  • 1
    [Enumerable.Range(Int32, Int32)](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.range) + `.Select()`. You can use the progressive value to index your `List`. – Jimi May 01 '19 at 14:45
  • @BrianRogers I am waiting to populate it – Alex May 01 '19 at 14:46
  • @Jimi can you elaborate more please? – Alex May 01 '19 at 14:46
  • Are you sure, that you want to copy the index into your models? If you need the index when accessing the list, you can do it like so: `myCars.Select((car, index) => new {car, index}).First(myCondition).index;`. https://stackoverflow.com/questions/2471588/how-to-get-index-using-linq – Christoph Lütjen May 01 '19 at 14:46
  • @Jimi Nice, I didn't know about Range() – Whelkaholism May 01 '19 at 14:47
  • @ChristophLütjen I need to change the order of the list to work with it, and then return it back to its original order – Alex May 01 '19 at 14:47
  • Do you need to change the order of the list to work with it? If you start off with the items in a list in the order you want, you can create other lists containing the same items in any other order, and the original list still has them in the order they started in. – Scott Hannen May 01 '19 at 15:24
  • @ScottHannen I am editing parts of the list after reordering. How would I then re order it to return it back to its original order? – Alex May 01 '19 at 15:25
  • That's the beauty of it. You don't need to do that. If you created a list in the order you wanted, don't sort it. If you need the same items in a different order, just add them to another list. – Scott Hannen May 01 '19 at 15:34
  • I wonder, why are you even having the index in there? What does it refer to? position of itself in a list of itself? What is the use of that? In my opinion, it only makes the class unclear and it's suddenly cross dependent on something else? If you want to find value by reference, why not use a Dictionary object? – Fabo.sk May 01 '19 at 16:24

3 Answers3

1

You can use Select. It has an overload that supplies the index value.

var values = new string[] { "foo", "bar", "baz" };

var dataStoreList = values.Select((v, i) => new DataStore { index = i, value = v }).ToList();
Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
1

I'm going to split hairs just a little bit. It sounds like what you want is a list of items in which the index represents an item's position in the list. The first item is 0, the next one is 1, etc. This requirement is important enough that you're writing code for it.

But the result is a List<DataStore>. What happens if the contents of the list get modified? Items could be added at the end, inserted in the middle, or deleted. The items added could have incorrect indexes or no index. Or you could change the index of an item at any time.

Also, what happens if the same object is in more than one list? Its index will probably be wrong in one list or the other.

The result is that nothing enforces the correctness of your indexes. What are some ways to address that?

The underlying problem is than an individual item doesn't "know" that it's included in a list, or what its position is within the list. The list itself is in a better situation to know the index of the items within it.

One possibility is this:

var positionOfItemInList = myList.IndexOf(item);

The list already knows the position of each item in it. The above will always indicate the position of an item in the list.

Another option would be to make the Index property read-only, set it when the item is created, and then encapsulate the list in a another class so that it is only exposed as a read-only collection. At least that way you can ensure that the index is accurate in relation to one list. (You could still add items from the list to another list, and then the index would be meaningless.)

But the underlying point is that for an item to maintain its own index creates the risk that the index is wrong or meaningless.

Also, someone looking at the class in isolation might wonder what Index is. It would be unclear because technically Index means nothing within the context of the class itself.


Adding on because of a few comments that clarify the intent. This is completely different way of looking at the underlying requirement.

Sometimes when we need to sort items in Excel we might first add an extra column and fill it with a sequence of numbers so that we can re-sort it back into its original order. That's similar to what you're doing when you add an index property.

But that's often unnecessary when we're dealing with reference types. Here's an example:

Suppose this object represents a test result, and you have a list of them in some order that you don't want to change:

public class TestResult
{
    public DateTime Completed { get; }
    public TimeSpan Duration { get; }
    public decimal Score { get; set; }
}

Most of the time we don't need an extra property on the object to tell us what order it was in. It may not be a good property to have because it doesn't actually describe the test score at all. It just describes the position of the object in some collection, and that property may or may not even be correct.

What if we have the list and we want to operate on it according to some particular sequence? Instead of sorting it and sorting it back, we can just create a new list with the same items.

public void DoStuffWithListOfTestScores(List<TestResult> testResults)
{
    // testResults is in some specific order and we don't want to change it.

    AddBonusForFinishingFaster(testResults);

    // the order of testResults hasn't changed.
}

private void AddBonusForFinishingFaster(IEnumerable<TestResult> testResults)
{
    var fastestTen = testResults.OrderBy(result => result.Duration).Take(10);
    foreach (var result in fastestTen)
    {
        result.Score += 10;
    }
}

We haven't solved the problem of how to add an index to each item. We've made the problem disappear and avoided adding properties we may not need.

Scott Hannen
  • 27,588
  • 3
  • 45
  • 62
0

I think you are looking for Enumerable.Range

var list = Enumerable
    .Range(0, 10)
    .Select(q => new DataStore { index = q })
    .ToList();

It will create a list with 10 entries.

koryakinp
  • 3,989
  • 6
  • 26
  • 56