Copy IEnumerables or ICollections into an EXISITING array entry-wise - c#

I have two IEnumerables already filled and an array large enough to store all elements of both of them:
IEnumerable<int> foo = ... // contains some elements.
IEnumerable<int> bar = ... // contains some elements.
int[] array = ... // already existing. array.Length is at least foo.Count + bar.Count
I want to copy the elements of foo and bar into array. And I would like to be able to do this without creating new objects (like LINQ would do when calling Concat or ToArray). In my concrete scenario, I do not care about the order, as it will be sorted later. A way to achieve it is this:
int k = 0;
foreach (int i in foo)
array[k++] = i;
foreach (int i in bar)
array[k++] = i;
I would like to know if there is some built-in method that does the copying for me (for convenience purposes), similar to LINQ ToArray or Concat, but without needing to create new objects. Giving ranges as input would be nice, too. A method like below maybe?
// desired way:
foo.InsertIntoArray(0) // insert the elements of foo into array starting at index 0
bar.InsertIntoArray(foo.Count) // insert the elements of bar into array starting at index foo.Count
I know the Array.Copy method, but as far as I know, it only works to copy from array to array, not from IEnumerable to array. Is there something alike?

List<int> foo = new List<int> { 1, 2, 3 };
List<int> bar = new List<int> { 3, 4, 5 };
//This will give you all items from both collections
var array = Enumerable.Concat(foo, bar).ToArray(); // 1,2,3,3,4,5
var array = foo.Concat(bar).ToArray();
//This will give you all distinct items
var array = Enumerable.Union(foo, bar).ToArray(); //1,2,3,4,5
var array = foo.Union(bar).ToArray();
You can also:
List<int> result = new List<int>();
result.AddRange(foo);
result.AddRange(bar);
result.InsertRange(result.Count, foo);
result.InsertRange(result.Count, bar);
foo.AddRange(bar); //But was assuming you don't want to change the existing list
But Both InsertRange and AddRange reallocate the internal array - And I assume Concut/Union use these behind the scenes

If your IEnumerable object also implements ICollection, you can cast it to ICollection and use the CopyTo method provided by this interface, otherwise you can only write loops. I actually looked at the source code for Enumerable.ToArray, and that's what Microsoft does.

Related

C# Using array.Where in Arraylist

I have sets of codes in C# with array and I need to split the array into smaller size array.
I have no errors when declaring the array with :
List<int> array = new List<int>();
However, the code execution prompts out error at the array.Where when I declare as :
var array = new ArrayList();
Is there any way I can use array.Where in array list? Below is my code :
List<int> array = new List<int>();
for (int i = 0; i <=20; i++){
if (unitIsPresent)
{
array.add(1);
}
else
{
array.add(0)
}
}
devidedArray = array.Where((e, i) => i >= 5 && i < 10).ToArray();
Array List is a non generic collection type so it's good to store items in array where you don't consider the items types. So for this reason you can't use Linq methods that are used for generics collections like Where.
My recommendation is use a List and convert it to Array with the Linq method provided.this way is very fast.
If you really want to use an ArrayList (really? why?), you can use OfType<int>() to change the IEnumerable to an IEnumerable<int>.
var devidedArray = array.OfType<int>().Where((e, i) => i >= 5 && i < 10).ToArray();
Alternatively you could use Cast<int>():
var devidedArray = array.Cast<int>().Where((e, i) => i >= 5 && i < 10).ToArray();
The difference between the two is that OfType() will silently ignore objects that cannot be cast to int while Cast() will fail with an InvalidCastException.
https://learn.microsoft.com/en-us/dotnet/api/system.collections.arraylist?view=net-5.0
look microsoft doc.
We don't recommend that you use the ArrayList class for new development. Instead, we recommend that you use the generic List class. ...
just use List<T> to replace ArrayList.

How to Create A Merged Array from 3 Arrays with LINQ which is not zipped but based on Content Equality

I have three Arrays which should be merged into one result via Linq:
int?[] list1 = {0,1,2,3,4};
int?[] list2 = {2,3,4,5};
int?[] list3 = {3,4};
Result:
var result=
{
(0,null,null),
(1,null,null),
(2,2,null),
(3,3,3),
(4,4,4),
(null,5,null)
}
Let's start by defining our input in a little more generic terms: a list of a list of integers. Since we don't need to modify these collections, we'll use the simplest interface that gives us what we need, IEnumerable<T>. That means our input is going to be: IEnumerable<IEnumerable<int?>>. Our output is going to be the same.
So now, let's define a prototype for the method that will do the work:
public static IEnumerable<IEnumerable<int?>> Merge(IEnumerable<IEnumerable<int?>> source) { //... }
Immediately I've noticed something: we don't really need to use int? since all we care about is checking equality, and all types support that, so we can make this method generic, and support any type:
public static IEnumerable<IEnumerable<T>> Merge<T>(IEnumerable<IEnumerable<T>> source) { //... }
Now let's start with the implementation, first we will need to compute every distinct value from all the lists:
source.SelectMany(x=>x).Distinct()
Now, for each of those values we need to return a collection with an item for each item in the original 'super list':
source.SelectMany(x=>x).Distinct().Select(x=>source.Select(y=> //...
So what do we need in that final Select lambda? We have x as each distinct integer (or technically T), and y as each original collection. We want the value x if the y collection contains x, otherwise, null (or to allow value types too, default(T). We can do that with a ternary:
source.SelectMany(x=>x).Distinct().Select(x=>source.Select(y=>y.Contains(x)?x:default(T)));
Putting it all together:
public static IEnumerable<IEnumerable<T>> Merge<T>(this IEnumerable<IEnumerable<T>> source)
{
return source
.SelectMany(x=>x)
.Distinct()
.Select(x=>source
.Select(y=>y.Contains(x)?x:default(T)));
}
And you can call it like so:
int?[] list1 = {0,1,2,3,4};
int?[] list2 = {2,3,4,5};
int?[] list3 = {3,4};
var result = new []{ list1, list2, list3 }.Merge();
Console.WriteLine(string.Join(Environment.NewLine, result.Select(t=>string.Join(",", t))));
First put all your arrays into one:
var lists = new[] { list1, list2, list3 };
Now loop all possible numbers and check if check if they are contained in the appropriate arrays. If so, you can add that number to your result, otherwise add null:
var result = new List<List<int?>>();
for(int i = 0; i < 6; i++)
{
result.Add(new List<int?>());
for(int j = 0; j < 3; j++)
{
if(lists[j].Contains(i))
result[i].Add(i);
else
result[i].Add(null);
}
}
I suppose this is pretty straightforward. Doing this is linq will just overcomplicate things, looks ugly and is hard to debug and understand. I doubt it´s a good idea to do so.

Collect indexes from list

Is there a linq function in c# which enables you to collect IEnumerables from a specific range of indexes?
An example would be
var objectArray = new string[] { "Bill", "Bob", "Joe", "Phil", "Tom", "Paul" };
var indexArray = new int[] { 1, 3, 5 };
var list = objectArray.Where(SOME_FUNCTION_TO_GET_INDEXES ??).ToList();
//output would be list:
//Bob
//Phil
//Paul
Just use Select with your indexArray and return the item from objectArray via indexing.
var list = indexArray.Select(i => objectArray[i]);
Note that this works very efficiently for any collection that allows indexing (for example, Array and List<T>). In the more general case of having an IEnumerable or ICollection, you wouldn't be able to index directly. In which case you'd need to see Jon's answer. Depending on the sizes of the lists involved, and how many items you need to look up, it might be worth converting your IEnumerable to an Array or List (using ToArray for example) first.
If the original datasource is already accessible by index, such as for a list or an array, you can just use indexArray.Select as Matt showed.
If you've got an IEnumerable<T> instead, you can use the Where overload which provides the index as well as the value. So:
var list = objectArray.Where((value, index) => indexArray.Contains(index))
.ToList();

How to get the data from list without using iterator in c#

i have a list contains set of strings, i want to fetch the data present in the list based on index, with out using iterator.. is there any functions like get() or getat() some sort of method using which we can fetch?
myList[index] is the way to go
List<string> myList = new List<string>();
myList.Add("string 1");
myList.Add("String 2");
Console.WriteLine(myList[0]); // string 1
Console.WriteLine(myList[1]); // String 2
List<string> myList = new List<string();
//add some elements to the list
//then get the third element
string thirdElement = myList[2];
You can just do:
item = list[i];
Use the overloaded index operator.
List<String> list; // ... initialize, populate list
String element = list[1]; // get the element at index 1
If your collection implements IList<T>, just use indexer. Otherwise, if your collection only allows forward-only access (that is, only implements IEnumerable<T>) you can use ElementAt() method, but it still uses iterator under the hood.
I don't know what kind of list you're talking about exactly, but most collections in .net have a CopyTo function, and you can access individual items with the [] operator.
List<string> list = new List<string>();
list.Add("lots of strings");
//If you want to print all the strings you can do:
foreach(string str in list)
Console.WriteLine(str);
//If you want to modify each string in the list, make each lower case for example,
// you can do. this is working by using the index of the elements in the list:
for(int i = 0; i < list.Count; i++)
list[i] = list[i].ToLower();
If you use the generic type List (or another implementation of IList) you can use the index operator to directly access items at certain positions: item = myList[3]
If you use a type that only implements IEnumerable you should use the ElementAt() function.
What's your reason to avoid the use of iterators?

'Cropping' a list in c#

Given a Generic IList of some type, which contains a number of items, is there any way of 'cropping' this list, so that only the fist x items are preserved, and the rest discarded?
If you can use Linq, it's just a matter of doing
// Extraact the first 5 items in myList to newList
var newList = myList.Take(5).ToList();
// You can combine with .Skip() to extract items from the middle
var newList = myList.Skip(2).Take(5).ToList();
Note that the above will create new lists with the 5 elements. If you just want to iterate over the first 5 elements, you don't have to create a new list:
foreach (var oneOfTheFirstFive in myList.Take(5))
// do stuff
The existing answers create a new list containing a subset of items from the original list.
If you need to truncate the original list in-place then these are your options:
// if your list is a concrete List<T>
if (yourList.Count > newSize)
{
yourList.RemoveRange(newSize, yourList.Count - newSize);
}
// or, if your list is an IList<T> or IList but *not* a concrete List<T>
while (yourList.Count > newSize)
{
yourList.RemoveAt(yourList.Count - 1);
}
you have a very simple way to:
IList<T> list = [...]; //initialize
IList<T> newList = new List<T>(max);
for (i=0; i<max; i++) newList.Add(list[i]);
Note: max MUST be less or equal then list length (otherwise you get IndexOutOfBoundsException)
If you need to do it just with the IList<T> interface, then something like this is the solution:
for (int i = list.Count - 1; i >= numberOfElementsToKeep; --i) {
list.RemoveAt(i);
}
Working backwards from the end of the list here, in order to avoid moving around data which will be deleted in subsequent loop iterations.

Categories