Arraylist in arraylist sorting - c#

I have an arraylist. it keeps arraylists in it. For example;
ar1 -> {2,3,46,67} keeps 4 members.
ar2 -> {28,96,67} keeps 3 members.
ar2 -> {56,32,67,54,214} keeps 5 members.
Ar_main[0]= ar1
Ar_main[1]= ar2
Ar_main[2]= ar3
i want to sort ar_main order by count of members. i used bubble sort algorithm. but it didn't work, can't we sort arraylist like this method?
private void sortArrayToAscending(ArrayList ar)
{
ArrayList ar1,ar2;
for (int i = 0; i < ar.Count - 1; i++)
for (int j = 1; j < ar.Count - i; j++)
{
ar1 = (ArrayList)ar[j];
ar2 = (ArrayList)ar[j-1];
if (ar1.Count < ar2.Count)
{
ArrayList temp = ar2;
ar2=ar1;
ar1=temp;
}
}
}

There is a built-in Sort method in the ArrayList that does the sorting for you. What you have to provide is an IComparer implementation that compares the list, making their length the criteria:
public void ArrayListSort()
{
var list = new ArrayList();
list.Sort(new LengthComparer());
}
class LengthComparer : IComparer
{
public int Compare(object x, object y)
{
var a = x as ArrayList;
var b = y as ArrayList;
// check for null if you need to!
return a.Count.CompareTo(b.Count);
}
}
However, unless you're actually using .NET 1.1, I'd recommend that you use List<T> instead of ArrayList, and the LINQ OrderBy method. This is type-safe, and I'd consider it more idiomatic C# nowadays. On top of that, it's way shorter:
var typedList = new List<List<int>>();
var sortedList = typedList.OrderBy(i => i.Count).ToList();
Be aware that the former is an in-place sort (altering the original list), whereas the latter copies the result into a new list.

I'm not allowed to comment yet or else I would. C# contains a built in static method in the ArrayList class. It sorts using the QuickSort algorithm. You may want to give it a try and see if it helps.Microsoft API Documentation ArrayList.Sort()

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.

Copy 2d array of list

I have a list List<MyClass>[,] myarraylist; and it is filled.
I want to copy it to List<MyClass>[,] mycopy then change mycopy without changing myarraylist.
What is the quickest way of doing this?
It kind of depends on what you really want to do. You can easily clone the array:
List<MyClass> mcopy = new List<MyClass>[marraylist.GetUpperBound(0)+1,marraylist.GetUpperBound(1)+1];
for (int i = 0; i < marraylist.GetUpperBound(0); ++i)
{
for (int j = 0; j < marraylist.GetUpperBound(1); ++j)
{
mcopy[i,j] = marraylist[i,j];
}
}
Now, that gives you a copy of the array. But, mcopy[1,2] has a reference to the same list as does marraylist[1,2]. If you modify that list, that is if you were to write:
mcopy[1,2].Add(new MyClass(...));
Then that would also modify the list that is referenced in marraylist[1,2].
If you want to create copies of the lists, then the code in your inner loop has to be:
mcopy[i,j] = new List<MyClass>(marraylist[i,j]);
That creates a new list, so if you modify the list at mcopy[1,2], you don't modify the list in the original array.
But that might not be what you want, either. Because although mcopy[1,2] contains a different list than marraylist[1,2], the lists have the same contents. So if you wrote mcopy[1,2][1].SomeProperty = 42;, then you'll also modify the contents of the object at marraylist[1,2][1], because they're the same object.
If you want to copies of the lists and copies of the objects, then your inner loop code becomes:
mcopy[i,j] = marraylist[i,j].Select(m => new MyClass(/* create from m */)).ToList();
The /* create from m */ comment means that you either pass m to the copy constructor (if you have one), or pass the individual parameters, or if you have a clone method on the class you'll use that. Somehow you want to make a deep copy of the MyClass instance.
Yes, it's complicated. The word "copy" is quite overloaded here, and how you proceed depends entirely on what definition of "copy" you're using. Do you want to make a copy of the array (just copy the references), the array's contents (create new lists with the same objects), or the lists' contents (create new lists with new objects that contain the same data)?
If MyClass has a copy constructor:
var newList = new List<MyClass>[oldList.GetLength(0), oldList.GetLength(1)];
for (int i = 0; i < oldList.GetLength(0); i++)
for (int j = 0; j < oldList.GetLength(1); j++)
newList[i, j] = oldList[i, j].Select(x => new MyClass(x)).ToList();
If it doesn't have a copy constructor, and you can't add one, you will have to write your own function to make a copy of MyClass.
newList[i, j] = oldList[i, j].Select(x => CloneMyClass(x)).ToList();
This may work. It is an extension method to 2D IEnumerables. That means it can be used with anything that implements the IEnumerable interface, as long as your class T implements ICloneable.
public static IEnumerable<IEnumerable<T>> Clone<T>(this IEnumerable<IEnumerable<T>> twoDList) where T : ICloneable
{
if (twoDList != null)
{
List<List<T>> result = new List<List<T>>();
for (int i = 0; i < twoDList.Count(); i++)
{
List<T> aList = new List<T>();
for (int j = 0; j < twoDList.ElementAt(i).Count(); j++)
{
aList.Add(twoDList.ElementAt(i).ElementAt(j));
}
result.Add(aList);
}
return result;
}
else
{
return null;
}
}
It should also work with jagged 2D structures that implement IEnumerable.
Example Usage follows:
List<List<MyClass>> cloned = original2DStructure.Clone();
Help on making your class implement ICloneable could be found here.

Problem with custom IComparer for List (sort) - c#

can anyone help, i have problem doing a sort, I thought i had it sorted but appears not to be working.
I have a List which stores the following values
8,6,10,11,7
I also have another List (accessories in my class and it has a propert called accessoryId current the classes are in the order of id which is currenty 6,7,8,10,11)
Hence i need to sort them from 6,7,8,10,11 to the order used from the simple list which is 8,6,10,11,7
I have my icomparable (see below) and i am calling like this - it does enter but something is wrong BECAUSE the list still has all my classes but is still in the order of 6,7,8,10,11
// accesories is the IList<Accessories> (hence why i am use ToList)
// and sortOrder is the simple int list list<int>
accesories.ToList().Sort(new ItemTpComparer(sortOrder));
class ItemTpComparer : IComparer<Accessories>
{
private IList<int> otherList;
public ItemTpComparer(IList<int> otherList)
{
this.otherList = otherList;
}
#region IComparer<Accessories> Members
public int Compare(Accessories x, Accessories y)
{
if (otherList.IndexOf(x.AccessoryId) > otherList.IndexOf(y.AccessoryId))
return 1;
else if (otherList.IndexOf(x.AccessoryId) < otherList.IndexOf(y.AccessoryId))
return -1;
else
return 0;
// tried below also didn't work
//return otherList.IndexOf(x.AccessoryId) - otherList.IndexOf(y.AccessoryId);
The comparer is correct (even the commented single line version). The problem is ToList() creates a new List containing a copy of elements in the IEnumerable<T> object so basically, you are creating a new list, sorting it and throwing it away.
var sortedList = accesories.ToList();
sortedList.Sort(new ItemTpComparer(sortOrder));
for which I'd suggest replacing with:
var sortedList = accessories.OrderBy(sortOrder.IndexOf).ToList();
this way, no comparer implementation would be necessary. You could also sort in the descending order easily:
var sortedList = accessories.OrderByDescending(sortOrder.IndexOf).ToList();
If the object is really List<Accessories>, you could also sort it in place:
((List<Accessories>)accessories).Sort(new ItemTpComparer(sortOrder));
Mehrdad showed you why the list was not sorted. I want to address the performance of the comparer, and also the issue with less sorting items than sorted items.
Using IndexOf on a list to locate the index is quite inefficient. I has to loop through the items in the list to find the right one. Use a dictionary as lookup instead, that way you only loop through the items once:
class ItemTpComparer : IComparer<Accessories> {
private Dictionary<int, int> index;
public ItemTpComparer(IList<int> otherList) {
index = new Dictionary<int, int>();
for (int i = 0; i < otherList.Count; i++) {
index.Add(otherList[i], i);
}
}
public int Compare(Accessories x, Accessories y) {
return index[x.AccessoryId].CompareTo(index[y.AccessoryId]);
}
}
If you want to allow the list of value to sort by to be shorter than the list of items to sort, you check if the value exists in the dictionary:
public int Compare(Accessories x, Accessories y) {
int xIndex, yIndex;
if (!index.TryGetValue(x.AccessoryId, out xIndex)) xIndex = int.MaxValue;
if (!index.TryGetValue(y.AccessoryId, out yIndex)) yIndex = int.MaxValue;
return xIndex.CompareTo(yIndex);
}

How can I convert a list<> to a multi-dimensional array?

I have the following method signature:
public void MyFunction(Object[,] obj)
I create this object:
List<List<Object>> obj = new List<List<Object>>;
Is there an easy way I can convert this to an Object[,]?
UPDATE:
The fact is I like to use Lists because I can easily add a new item. Is there a way I can declare my List<> object to fit this need? I know the number of columns in my Object[,] but not the number of rows.
No. In fact, these aren't necessarily compatible arrays.
[,] defines a multidimensional array. List<List<T>> would correspond more to a jagged array ( object[][] ).
The problem is that, with your original object, each List<object> contained in the list of lists can have a different number of objects. You would need to make a multidimensional array of the largest length of the internal list, and pad with null values or something along those lines to make it match.
You're not going to get a very simple solution for this (i.e. a few lines). LINQ/the Enumerable class isn't going to help you in this case (though it could if you wanted a jagged array, i.e. Object[][]). Plain nested iteration is probably the best solution in this case.
public static T[,] To2dArray(this List<List<T>> list)
{
if (list.Count == 0 || list[0].Count == 0)
throw new ArgumentException("The list must have non-zero dimensions.");
var result = new T[list.Count, list[0].Count];
for(int i = 0; i < list.Count; i++)
{
for(int j = 0; j < list[i].Count; j++)
{
if (list[i].Count != list[0].Count)
throw new InvalidOperationException("The list cannot contain elements (lists) of different sizes.");
result[i, j] = list[i][j];
}
}
return result;
}
I've included a bit of error handling in the function just because it might cause some confusing errors if you used it on a non-square nested list.
This method of course assumes that each List<T> contained as an element of the parent List is of the same length. (Otherwise you really need to be using a jagged array.)
Here is a solution using Linq's Aggregate extension.
Note that the below does not check, nor is concerned if it gets a jagged sub list, it uses the max size of all the sublists and fills in according to the current list. If that is a concern one could add a check to the if to check for the same count amongst all the sub lists.
public static T[,] To2DArray<T>(this List<List<T>> lst)
{
if ((lst == null) || (lst.Any (subList => subList.Any() == false)))
throw new ArgumentException("Input list is not properly formatted with valid data");
int index = 0;
int subindex;
return
lst.Aggregate(new T[lst.Count(), lst.Max (sub => sub.Count())],
(array, subList) =>
{
subindex = 0;
subList.ForEach(itm => array[index, subindex++] = itm);
++index;
return array;
} );
}
Test / Usage
var lst = new List<List<string>>() { new List<string>() { "Alpha", "Beta", "Gamma" },
new List<string>() { "One", "Two", "Three" },
new List<string>() { "A" }
};
var newArray = lst.To2DArray();
Result:
To be blunt, the answer is no, not easily.
Perhaps you would like to edit your question to give us more background about why these declarations are needed and we can help you with your root problem?
Re your update:
I assume you cannot change the function you need to pass this into.
I don't see why you cannot just use an object[,] to begin with. This is my recommendation.
I doubt this will help you in your situation, but it might make some of the array working easier on you to start with. Do you know about the .ToArray() method on a List?

Categories