Removing items in Jagged array using index - c#

I want to remove items of a Jagged array using indizes.
int[] toRemove; (e.g, {0, 1})
int[][] MainArray (e.g. { [0] {...}, [1] {...}, [2] {...}}
Expected result
int[][] result (e.g. {[2] {...}}
From the MainArray how to remove the items which having indexes from the toRemove list?
Is there an efficient way using LINQ?

Hopefully this gives the expected result:
var notInToRemove = MainArray
.Where((arr ,index) => !toRemove.Contains(index)).ToArray();

You could use the ElementAt method instead of the Remove method if all you want is the data that is not to be there in the toRemove set.
int[] toRemove = {0,1};
int[][] mainArray = new int[3][];
mainArray[0] = new int[]{0,0,0};
mainArray[1] = new int[]{1,1,1};
mainArray[2] = new int[]{2,2,2};
var result = mainArray.ElementAt(2); // This value 2 is found as all indexes of mainArray except the values in toRemove
//(Code would look like this :
Enumerable.Range(0, mainArray.Length).Except(toRemove);

Related

How to add index range of one string list to another string list

I am new to c# and recoding some python into c#. How would you take a range of one list (list1) and create a new shorter list of it(list2)?
python
list1= ["lets", "go", "visit", "houston", "texas"]
list2 = []
list2.append(list1[3:4]) ##new list is ["houston", "texas"]
#or
list2.append(list1[3:]) ##new list is ["houston", "texas"]
How would this look in c#?
private void button1_Click(object sender, EventArgs e)
{
List < string > list1 = new List < string > ();
list1.Add("lets");
list1.Add("go");
list1.Add("visit")
list1.Add("houston");
list1.Add("texas");
List<string> list2 = list1.GetRange(3, 4);
}
Is there a better way to get list index ranges? And how to begin the index, list1[:3] or index to end list1[3:]
This would be the C# equivalent:
var list1 = new List<string> { "lets", "go", "visit", "houston", "texas" };
var list2 = new List<string>();
list2.AddRange(list1.Skip(3).Take(2 /* there is 2 elements from 3rd to 4th*/));
// or
list2.AddRange(list1.Skip(3));
Edit: You can extend the list with custom methods:
public static class ListExtensions
{
public static List<T> Slice<T>(this List<T> list, int? start = null, int? end = null)
{
if (start.HasValue)
return list.GetRange(start.Value, (end.HasValue ? (end.Value + 1) : list.Count) - start.Value);
if (end.HasValue) // not sure [:n] returns last n elements?
return list.GetRange(list.Count - end.Value, end.Value);
return list;
}
}
var list1 = new List<string> { "lets", "go", "visit", "houston", "texas" };
list1.Slice(3) // houston, texas
list1.Slice(3, 4) // houston, texas
list1.Slice(null, 3) // visit, houston, texas
You can do this using the GetRange method of List<T>:
List<string> list2 = list1.GetRange(3, 2); // Take two items starting at index 3
List<string> list2 = list1.GetRange(0, 3); // Take from the beginning up to index 3
List<string> list2 = list1.GetRange(3, list1.Count - 3); // Take from index 3 to the end
Or, alternatively, by using the Linq extension methods Skip and Take (using System.Linq):
List<string> list2 = list1.Skip(3).Take(2).ToList(); // Take two items starting at index 3
List<string> list2 = list1.Take(3).ToList(); // Take from the beginning up to index 3
List<string> list2 = list1.Skip(3).ToList(); // Take from index 3 to the end
Firstly, note that GetRange is defined as:
System.Collections.Generic.List<T> GetRange (int index, int count);
Where index is the zero-based List<T> index at which the range
starts.
count is the number of elements in the range.
Thus, you doing list1.GetRange(3, 4); will yield a System.ArgumentException: as count i.e. 4 does not denote a valid range of elements in the list.
Further, using GetRange is as good as it gets if you want to copy a specific range of a list.
In order to yield a list containing "houston" and "texas" you can call GetRange with 3 as the index and 2 as the count of elements.
list1.GetRange(3, 2); // ["houston", "texas"]
Unfortunately, there's no GetRange taking only a "begin index".
Instead, if you don't want to specify the Count in GetRange then use Skip then collect to a list:
list1.Skip(3).ToList(); // ["houston", "texas"]
Alternatively, if you want to add to an "existing" list then use AddRange + GetRange:
list2.AddRange(list1.GetRange(3, 2)); // ["houston", "texas"]
You can use the Array.Copy() method. This will allow you to copy a specified range of elements in one Array to another Array.
See documentation here.

Instantiating a List

If I want to instantiate a array the syntax is
int[] items = new int[] { 1, 2, 3 };
and the shortcut is
int[] items = {1,2,3};
Now I want to do the same to a List.
Question:
why does this work:
List<int> items = new int[] { 1, 2, 3 }.ToList();
but not this:
List<int> items = { 1, 2, 3 }; //invalid
or
List<int> items = { 1, 2, 3 }.ToList(); //invalid
The syntax
int[] array = {1,2,3};
is special syntactic sugar for array initialization. {1,2,3} is not itself an array yet.
This line
List<int> list = new[] {1,2,3}.ToList();
works because the expression new[] {1,2,3} returns an int[], which implements IEnumerable<int> and so you can call ToList() on it.
In the specs that's the difference between 12.6 Array initializers and 7.5.10.2 Array creation expressions.
List<T> has a constructor that takes an IEnumerable<T> as argument to initialize the list's content with. So you can either call
List<int> list = new List<int>(new[]{1,2,3});
or use the collection initializer syntax sugar:
List<int> list = new List<int> {1,2,3};
which is converted by the compiler to something like this:
var tmp = new List<int>();
tmp.Add(1);
tmp.Add(2);
tmp.Add(3);
List<int> list = tmp;

Two ArrayList manipulation

I have one ArrayList in Session, lets say for example [305,306,380].
On submit, user choice other products which i save them in 2nd array, for example [390,305,480,380]
How can i make another three arrays where
All new values [390,480]
All values which are in both lists [305,380]
All values from list1 which are not in list2 [306]
I need this in ASP.NET 4.0 C#
You can use ArrayList.ToArray() to get arrays against your arraylists. Then using LINQ you can easily get what you want withExcept an Intersect methods, for example
array2.Except(array1)
array1.Except(array2)
array1.Intersect(array2)
Edit: Complete Code
According to your requirement, your code may look-like this;
ArrayList arrayList1 = new ArrayList(new int[] { 305, 306, 380 });
ArrayList arrayList2 = new ArrayList(new int[] { 390, 305, 480, 380 });
int[] array1 = (int[])arrayList1.ToArray(typeof(int));
int[] array2 = (int[])arrayList2.ToArray(typeof(int));
//1. All New values
int[] uniqueInArray2 = array2.Except(array1).ToArray();
//2. Common values
int[] commonValues = array1.Intersect(array2).ToArray();
//3. Values of arrayList1 which are not in arrayList2
int[] uniqueInArray1 = array1.Except(array2).ToArray();
Use HashSet the folowing way:
var first = new HashSet<int>();
first.Add(...);
var second = ...;
1. second.ExceptWith(first);
2. first.IntersectWith(second);
3. first.ExceptWith(second);

other way to add item to List<>

In my other question You can see code of my arr structure and PriorityQueue collection. I normally add items to this collection like that:
arr.PriorityQueue.Add(new element((value(item, endPoint) + value(startPoint, item)),item));
I am curious that is other way to do this (add element(which is struct) object to List) ? In lambda way for example ? I just eager for knowledge :)
To add a new object to a list, you need to instantiate it.
The way you are doing it is correct, there is not lambda syntax or other syntactic sugar for this operation.
Another way is to use List.AddRange. It accepts an IEnumerable<T>, so you can pass it any collection of T, including arrays or the results of Linq expressions:
importantItems.AddRange(allItems.Where(item => item.IsImportant));
arrays arr = new arrays();
arr.PriorityQueue = new List<element>(
new [] {
new element {node = 1, priority =2 },
new element { node = 2, priority = 10}
//..
//..
});
arrays arr2 = new arrays();
arr2.PriorityQueue = new List<element>(
arr.PriorityQueue
);
arrays arr3 = new arrays();
arr3.PriorityQueue = new List<element>(arr2.PriorityQueue.FindAll(z => (1 == 1)));
arrays arr4 = new arrays();
arr4.PriorityQueue = new List<element>(arr3.PriorityQueue.ToArray());

Sorting an array related to another array

I have two arrays, x and y, where y is the value of the tens of every element in x. Now, I want to sort y. But, the order of y will be different of x's. So, I can't tell after sorting which element in y was related to, for instance, x[0].
I want a "double sorting" maybe.
Array.Sort has an overload that accepts two arrays; one for the keys, and one for the items. The items of both are sorted according to the keys array:
int[] keys = { 1, 4, 3, 2, 5 };
string[] items = { "abc", "def", "ghi", "jkl", "mno" };
Array.Sort(keys, items);
foreach (int key in keys) {
Console.WriteLine(key); // 1, 2, 3, 4, 5
}
foreach (string item in items) {
Console.WriteLine(item); // abc, jkl, ghi, def, mno
}
So in your case, it sounds like you want:
Array.Sort(y,x); // or Sort(x,y); - it isn't 100% clear
How about?
var selectedArr = new int[] { 1, 3, 5, 7, 9 };
var unorderArr = new int[] { 9, 7, 5, 3, 1 };
var orderedArr = unorderArr.OrderBy(o => selectedArr.IndexOf(o));
If we have two arrays of complex objects and want to sort them according to one of the two arrays then we can use the next approach:
// We want to sort "people" array by "Name" and
// accordingly to it reorder "countries" array.
Person[] people = new Person[]
{
new Person {Name = "Fill"},
new Person {Name = "Will"},
new Person {Name = "Bill"},
};
Country[] countries = new Country[]
{
new Country {Name = "Canada"},
new Country {Name = "UK"},
new Country {Name = "USA"}
};
// Here we sort "people" array, but together with each "Person"
// in sorted array we store its "index" in unsorted array. Then we
// will use this "index" to reorder items in "countries" array.
var sorted = people
.Select((person, index) => new {person, index})
.OrderBy(x => x.person.Name)
.ToArray();
// Here "people" array is sorted by "Name", and
// "contries" array is reordered accordingly to it.
people = sorted.Select(x => x.person).ToArray();
countries = sorted.Select(x => countries[x.index]).ToArray();
Another approach is to use overload of the method Array.Sort with IComparer. At first we should implement IComparer:
private class PeopleComparer : IComparer<Person>
{
public int Compare(Person x, Person y)
{
return x.Name.CompareTo(y.Name);
}
}
And then we can sort two our arrays:
Array.Sort(people, countries, new PeopleComparer());
Here is complete sample that demonstrates these two approaches.
If y is always the tens value of x, y probably shouldn't exist - you should probably just calculate it's value directly off of x when needed.
In general, sorting parallel arrays is only possible (without hand rolling a sort algorithm) when the sort algorithm takes a custom "swap" function, which you can implement in terms of swapping elements in both arrays simultaneously. std::sort in C++ and qsort in C don't allow this.
Also in the general case, consider a single array where the element is a pair of items, rather than a parallel array for each item. This makes using "standard" algorithms easier.

Categories