I need to sort a list of objects and an arbitrary sort property. If there are multiple objects in my list that have the same value for that sort property, then repeatedly sorting the same list will rearrange the members with the same value of sort property. To be clear, each time sort is run, a new list is generated and the order of members is arbitrary and not necessarily the same as it was the last time the list was sorted. Is there a way to avoid this?
Here is a code sample:
List<T> myList; // T is arbitrary and I doesn't implement any common interface
PropertyInfo sortPorperty = some property of T
var sortedList = myList.OrderBy(x => sortProperty.GetValue(x));
Multiple executions of this code will result in different order of the objects.
My initial idea is to also sort by the object itself
var sortedList = myList.OrderBy(x => sortProperty.GetValue(x)).ThenBy(x => x);
But as far as I can tell that will sort by hashcode and that is basically the memory location of an object so it would not be the same between runs. Is there anything else that would work?
If the type is serializable then you can use the serialization of the object to serve as the final sort criteria.
Use BinaryFormatter to generate a unique string for the object (which I have called Idem in this example) and use that as the final .ThenBy sorting criteria.
In this example I transformed the binary formatted version of the object to a base64 string (that's performance overhead for sure, and there are other approaches to get the the binary versions to compare nicely, but I'm just illustrating the general approach.)
I think this example has everything you asked for. Arbitrary type with no interface, uses a property as the OrderBy criteria, and does not rely on the initial order of the items to produce the same order of the output on subsequent runs.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
public static class Extensions
{
// Returns a string unique(TM) to this object.
public static string Idem<T>(this T toSerialize)
{
BinaryFormatter formatter = new BinaryFormatter();
var memoryStream = new MemoryStream();
using (memoryStream)
{
formatter.Serialize(memoryStream, toSerialize);
return Convert.ToBase64String(memoryStream.ToArray());
}
}
}
[Serializable()]
public class Person
{
public Person(string name, string secret)
{
this.name = name;
this.secret = secret;
}
private string secret; // some private info
public string Nickname { get { return name; } } // some property
public string name; // some public info
public override string ToString() // a way to see the private info for this demo
{
return string.Format("{0} ({1})", name, secret);
}
}
class Program
{
static void Main(string[] args)
{
// You can rearrange the items in this list and they will always come out in the same order.
List<Person> myList = new List<Person>() {
new Person("Bob", "alpha"),
new Person("Bob", "bravo"),
new Person("Alice", "delta"),
new Person("Bob", "echo"),
new Person("Bob", "golf"),
new Person("Bob", "foxtrot"),
};
PropertyInfo sortProperty = typeof(Person).GetProperty("Nickname");
Random random = new Random();
for (int i = 0; i < 3; ++i)
{
var randomList = myList.OrderBy(x => random.Next());
var sortedList = randomList.OrderBy(x => sortProperty.GetValue(x))
.ThenBy(x => x.Idem()); // Here's the magic "Then By Idem" clause.
Console.WriteLine(string.Join(Environment.NewLine, sortedList));
Console.WriteLine();
}
}
}
Related
I'm instantiating an object with properties coming from a IEnumerable. The straightforward way is
IEnumerable<string> source = ...
var instance = new X(
source.First(),
source.Skip(1).First(),
source.Skip(2).First(),
...
);
Where X is a class with a constructor that takes a number of parameters.
This works, but it feels like this is a common scenario (for example fetching data using a generic storage layer and instantiating a specific record type) that there should be a cleaner way.
I considered making a list using a .ToList() and then access the properties using the indexer, but that evaluates the whole Enumerable which I don't feel is warranted here.
Is there a cleaner approach? I was imagining an Enumerator approach that would allow me to .MoveNext() & .Current approach, that would allow me O(1) access and no unnecessary allocations -- but with some syntax sugar to make that pretty
It looks like you're trying to take the first N values from the series, for some value of N.
If the X(...) takes a params string[], then you can just use source.Take(N).ToArray(); since we'll be building the array anyway, this has no particular additional overhead.
If the X(...) takes N separate string parameters, then you do need to unroll it, but iterating the sequence multiple times is awkward. It may be ugly, but I'd probably use something custom here:
string a, b, c;
using (IEnumerator<string> iter = source.GetEnumerator())
{
a = iter.Next();
b = iter.Next();
c = iter.Next();
}
return new X(a, b, c);
static class Utils
{
public static T Next<T>(this IEnumerator<T> source)
{
if (!source.MoveNext()) Throw();
return source.Current;
static void Throw() => throw new InvalidOperationException("Missing element from sequence");
}
}
You could also move the constructor inside the using, if you don't mind extending the sequence living a little longer (into the constructor invoke):
using IEnumerator<string> iter = source.GetEnumerator();
return new X(iter.Next(), iter.Next(), iter.Next());
You can pass parameters via activator.createinstanc<T>
See here: https://learn.microsoft.com/en-us/dotnet/api/system.activator.createinstance?redirectedfrom=MSDN&view=net-7.0#System_Activator_CreateInstance_System_Type_System_Object___
Try this:
using System;
using System.Collections.Generic;
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public Person(string firstName, string lastName, int age)
{
FirstName = firstName;
LastName = lastName;
Age = age;
}
}
class Program
{
static void Main(string[] args)
{
List<object> constructorArgs = new List<object>() { "David", "Božjak", 30 };
Person p = (Person)Activator.CreateInstance(typeof(Person), constructorArgs.ToArray());
Console.WriteLine($"{p.FirstName} {p.LastName} is {p.Age} years old.");
}
}
Assuming I have an object class MyObject with the following properties:
class MyObject {
public int MyProperty1 { get; set; }
public int MyProperty2 { get; set; }
public int MyProperty3 { get; set; }
}
And I have an array of MyObject[] with the following elements:
MyObject[] myObjects => new MyObject[] { myObject1, myObject2, myObject3 };
How do I create a new instance myObject such that its MyProperty1, MyProperty2, and MyProperty3 are the sums of the respective properties for every such object in the array?
Currently, my implementation is as follows
MyObject MyObjectSummed => new MyObject()
{
MyProperty1 = myObjects.Sum(x => x.MyProperty1);
MyProperty2 = myObjects.Sum(x => x.MyProperty2);
MyProperty3 = myObjects.Sum(x => x.MyProperty3);
}
but I vaguely remember seeing a more efficient way of doing this using LINQ, using a single line of code.
Is this possible and can someone please point me in the right direction?
Thanks!
You need to update three properties, so having "one-liner" will make code very unreadable.
If asking about different LINQ approach instead of summarising three values, then Aggregate is your choice, check #Andy's answer.
If you wrap logic with the method then you can use any amount of lines inside the implementation, but keep it one-liner for the consumers.
Alternative approach can be an extension method for enumerable
public static MyObject CalculateSum(this IEnumerable<MyObject> objects)
{
var total = new MyObject();
foreach (var obj in objects)
{
total.MyProperty1 += obj.MyProperty1;
total.MyProperty2 += obj.MyProperty2;
total.MyProperty3 += obj.MyProperty3;
}
return total;
}
Usage is "one-liner" :)
var objects = new MyObject[] { myObject1, myObject2, myObject3 };
var sum = objects.CalculateSum();
Notice that all LINQ methods are extension methods, so you kinda using your own domain specific LINQ "one-liner" ;)
So if you do not want to mutate the original array, this is what you can do:
var result = myObjects.Aggregate(new MyObject(), (accumulate, current) => {
accumulate.MyProperty1 += current.MyProperty1;
accumulate.MyProperty2 += current.MyProperty2;
accumulate.MyProperty3 += current.MyProperty3;
return accumulate;
});
If you do not care you can just do this:
By doing this way you are mutating the first element within the array.
var result = myObjects.Aggregate((accumulate, current) => {
accumulate.MyProperty1 += current.MyProperty1;
accumulate.MyProperty2 += current.MyProperty2;
accumulate.MyProperty3 += current.MyProperty3;
return accumulate;
});
If performance is not an issue, you can use reflections. Then you can add and remove integer properties to your object without having to modify the code of adding. If you convert the return value of GetProperties() to a list, you can use the ForEach() method of List<T>, which even reduces your line count further.
MyObject myObjectSummed = new MyObject();
foreach(var prop in myObjectSummed.GetType().GetProperties().Where(p => p.PropertyType == typeof(int)))
{
prop.SetValue(myObjectSummed, myObjects.Sum(x => (int)prop.GetValue(x)));
}
But i recommend Fabio's answer: From my point of view, it's clearest way to write this logic. Having as few lines of code as possible is not always the best approach.
I am trying to sort an ArrayList using c#. When the ArrayList contains comparable objects, it is possible to sort with using list.Sort() but I need to sort an ArrayList which contains non-comparable objects. For example, let's say the object is Ring and it has an attribute property Price. Then I need to sort the ArrayList to the price order. If is is possible to select ascending or descending that will more helpful. Thank You!
Blockquote
arrAtdMon = **(ArrayList)**hashTb[unixMon];
if (arrAtdMon != null)
monCount = arrAtdMon.Count;
int[] arrayMax = { monCount, tueCount, wedCount, thuCount, friCount };
int maxValue = arrayMax.Max();
KidAttendance valMon = null;
string monTagName = string.Empty;
Blockquote
above array list is to be sorted it self.
You can do this by implementing IComparer interface:-
public class Ring : IComparer
{
public decimal Price { get; set; }
public int Compare(object x, object y)
{
return ((Ring)x).Price.CompareTo(((Ring)y).Price);
}
}
Working Fiddle.
First, you really should be using the List<T> class, not ArrayList. Doing so wouldn't solve your problem, but it would make the code less fragile and more easy to maintain.
As for the specific question, you want to do something like this…
Assume:
class Ring { public decimal Price { get; set; } }
Then:
ArrayList list = ...; // Initialized as some collection of Ring instances
list.Sort(Comparer.Create((r1, r2) => r1.Price.CompareTo(r2.Price)));
This creates a new Comparer instance using the Comparison<T> of (r1, r2) => r1.Price.CompareTo(r2.Price). That is, for each pair of objects being compared, compare the price of the first with the price of the second.
Assuming that these objects share a base class or an interface with the price property you should be able to do something like this:
// Base class with price property, could also be an shared interface
public abstract class Product
{
public decimal Price{get;set;}
}
public class Ring : Product
{
}
public class Bag : Product
{
}
// Some test data
var myUnsortedArray = new Product[]{new Ring{Price = 1.2m}, new Bag{Price=2.5m}};
// Easy sort with LINQ
var sortedProducts = myUnsortedArray.OrderBy(p => p.Price).ToArray();
var sortedProductsDescending = myUnsortedArray.OrderByDescending(p => p.Price).ToArray();
UPDATE
I just realised that the question is about ArrayLists and have the changed solution below:
// Some test data
var myUnsortedArrayList = new ArrayList{new Ring{Price = 1.2m}, new Bag{Price=2.5m}};
// Easy sort with LINQ
var sortedProducts = myUnsortedArrayList.OfType<Product>().OrderBy(p => p.Price).ToArray();
var sortedProductsDescending = myUnsortedArrayList.OfType<Product>().OrderByDescending(p => p.Price).ToArray();
To sort an set of objects, the object needs to be Comparable and you can set up the comparison you'd like in the CompareTo() method:
IComparable information here
Currently I have object which contains two strings:
class myClass
{
public string string1 { get; set; }
public string string2 { get; set; }
public bool MatcheString1(string newString)
{
if (this.string1 == newString)
{
return true;
}
return false;
}
}
I then have a second class that makes a list of the aforementioned object using List.
class URLs : IEnumerator, IEnumerable
{
private List<myClass> myCustomList;
private int position = -1;
// Constructor
public URLs()
{
myCustomList = new List<myClass>();
}
}
In that class I’m using a method to check if a string is present in the list
// We can also check if the URL string is present in the collection
public bool ContainsString1(string newString)
{
foreach (myClass entry in myCustomList)
{
if (entry. MatcheString1(newString))
{
return true;
}
}
return false;
}
Essentially, as the list of objects grows to the 100,000 mark, this process becomes very slow. What is fast way to checking if that string is present? I’m happy to create a List outside of the class to validation, but that seems hacky to me?
Once the list of items is stable, you can compute a hash-set of the matches, for example:
// up-front work
var knownStrings = new HashSet<string>();
foreach(var item in myCustomList) knownStrings.Add(item.string1);
(note that this is not free, and will need to be re-computed as the list changes); then, later, you can just check:
return knownStrings.Contains(newString);
which is then very cheap (O(1) instead of O(N)).
If you don't mind using a different data structure, instead of a list, you could a dictionary where your objects are indexed by their string1 property.
public URLs()
{
myDictionary = new Dictionary<string, myClass>();
}
Since Dictionary<TKey, TValue> can usually find elements in O(1) time, you can perform that check very fast.
if(myDictionary.ContainsKey(newString))
//...
Search over sorted array(list) takes O(logN)
var sortedList = new SortedSet<string>();
sortedList.Add("abc");
// and so on
sortedList.Contains("test");
Search over HashSet takes O(1), but I guess in case of 100k elements(Log(100000)=5), and almost no difference to the HashSet that takes more memory.
I need to make a copy of a MyGame class and use it in my simulation for game trials before I select a move to play.
For example :
public class MyGame
{
private int Start;
private Board board;
//Constructor
public void Play()
{
//play game
}
public object Clone()
{
}
}
public class Board
{
private int Count;
//Constructor
//Some methods and properties
public object Clone()
{
}
}
Writing code for the method Clone() I have tried
MemberwiseClone()
(Board) this.MemberwiseClone()
Board b = (Board) this.Board
I have read alot of articles and forums about this topic. The answer most people
use is Deep cloning objects in C#, I tried samples with respect to my project but I still
get my simulation modifying the original object (MyGame Class) and not the copy.
Here I have an example for a deep copy, which deeply copies all reference type objects that are used with a copy constructor:
public sealed class MyGame
{
private int start;
private Board board;
public MyGame(MyGame orig)
{
// value types - like integers - can easily be
// reused
this.start = orig.start;
// reference types must be clones seperately, you
// must not use orig.board directly here
this.board = new Board(orig.board);
}
}
public sealed class Board
{
private int count;
public Board(Board orig)
{
// here we have a value type again
this.count = orig.count;
// here we have no reference types. if we did
// we'd have to clone them too, as above
}
}
I think your copy might be somehow shallow and re-use some references (like for instance this.board = orig.board instead of creating a new board). This is a guess though, as I can't see your cloning implementation.
Furthermore, I used copy constructors instead of implementing ICloneable. The implementation is almost the same. One advantage though is that you simplify dealing with subclasses:
Suppose you had a MyAwesomeGame : MyGame, not overriding MyGame.Clone. What would you get from myAwesomeGame.Clone()? Actually, still a new MyGame because MyGame.Clone is the method in charge. One may carelessly expect a properly cloned MyAwesomeGame here, however. new MyGame(myAwesomeGame) still copies somehow incompletely, but it's more obvious. In my example I made the classes sealed to avoid this failures. If you can seal them, there's good change it will make your life simpler.
Implementing ICloneable is not recommended in general, see Why should I implement ICloneable in c#? for more detailed and general information.
Here I have an ICloneable approach anyway, to make things complete and enable you to compare and contrast:
public class MyGame : ICloneable
{
private int start;
private Board board;
public object Clone()
{
var copy = new MyGame();
copy.start = this.start;
copy.board = (Board)this.board.Clone();
return copy;
}
}
public class Board : ICloneable
{
private int count;
public object Clone()
{
var copy = new Board();
copy.count = this.count;
return copy;
}
}
The simplest and most reliable way to implement deep cloning is to serialize, and then deserialize your objects. This can have a large performance cost associated with it. Consider classes from this namespace for serialization http://msdn.microsoft.com/en-us/library/System.Xml.Serialization.aspx
Deep cloning requires recursively creating a new instance of every property that is not a value type. Cloning MyGame would require a new instance of MyGame and a new instance of Board, both populated with the same Start and Count values as their originals. This is fiddly and a nightmare to maintain. As you can guess, it is not an automatic process out of the box but it can be, using reflection (which is how the xml serialization above works.
MemberwiseClone only creates a new instance of the object you called it on - all references remain the same.
MemberwiseClone() creates a stupid shallow clone of each member of an object. This works fine when members are value types but in case of reference types it fails because it'll clone pointers and not pointed objects.
Starting from your code a memberwise clone is something like this:
public object Clone()
{
MyGame cloned = new MyGame();
cloned.Start = this.Start; // Copied (cloned) because value type
cloned.Board = this.Board; // This is not a copy, just a reference!
}
A better solution for a deep clone would be to implement ICloneable (for example, otherwise a copy constructor approach is also good) for each reference type, let's suppose Board is cloneable too:
public object Clone()
{
MyGame cloned = new MyGame();
cloned.Start = this.Start;
cloned.Board = (Board)this.Board.Clone();
}
Please note that in your example Board can implement Clone() using MemberwiseClone() because its members are all value types.
If you can't manage this (for example because code is not accesible) or you need a quick/dirty solution you may consider to user serializaiton (in memory). Which serializer is a big question, each one has some limitations (about what's serialized and how). For example XML serializer won't serialize private fields (it won't serialize fields at all). Faster one is binary formatter but you need to mark each class with a proper attribute.
Change according serializer you prefer (according to your requirements), in this case I assume you marked MyGame and Board as [Serializable] for the quick binary serialization:
public object Clone()
{
using (var stream = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(stream, this);
stream.Seek(0, SeekOrigin.Begin);
return formatter.Deserialize(stream);
}
}
Try this
public static T DeepCopy<T>(this T obj)
{
T result;
var serializer = new DataContractSerializer(typeof(T));
using (var ms = new MemoryStream())
{
serializer.WriteObject(ms, obj);
ms.Position = 0;
result = (T)serializer.ReadObject(ms);
ms.Close();
}
return result;
}
I have two extension methods that I use to achieve this. Demo code below:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
namespace SimpleCloneDemo
{
public class Program
{
public static void Main(string[] args)
{
var person = new Person { Id = 1, FirstName = "John", Surname = "Doe" };
var clone = person.Clone();
clone.Id = 5;
clone.FirstName = "Jane";
Console.WriteLine(#"person: {0}", person);
Console.WriteLine(#"clone: {0}", clone);
if (Debugger.IsAttached)
Console.ReadLine();
}
}
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
public override string ToString()
{
return string.Format("Id: {0}, Full Name: {1}, {2}", Id, Surname, FirstName);
}
}
public static class ObjectExtensions
{
public static T Clone<T>(this T entity) where T : class
{
var clone = Activator.CreateInstance(entity.GetType());
var entityPropValueDictionary = entity.AsPropValueDictionary();
foreach (var prop in clone.GetType().GetProperties())
{
clone.GetType().GetProperty(prop.Name).SetValue(clone, entityPropValueDictionary[prop.Name]);
}
return clone as T;
}
public static IDictionary<string, object> AsPropValueDictionary<T>(this T instance, params BindingFlags[] bindingFlags)
{
var runtimeBindingFlags = BindingFlags.Default;
switch (bindingFlags.Count())
{
case 0:
runtimeBindingFlags = BindingFlags.Default;
break;
case 1:
runtimeBindingFlags = bindingFlags[0];
break;
default:
runtimeBindingFlags = bindingFlags.Aggregate(runtimeBindingFlags, (current, bindingFlag) => current | bindingFlag);
break;
}
return runtimeBindingFlags == BindingFlags.Default
? instance.GetType().GetProperties().ToDictionary(prop => prop.Name, prop => prop.GetValue(instance))
: instance.GetType().GetProperties(runtimeBindingFlags).ToDictionary(prop => prop.Name, prop => prop.GetValue(instance));
}
}
}
Result:
I wrote these quick-and-dirty extension methods in a hurry so there are probably some issues with it and they are probably horribly inefficient, but they seemed to work for my use case. They may help you, too.