I'm managing a data structure that looks like the following
[
{
"name": "Yada yada",
"dataModels": [
{
"entity": "Table",
"columns": [
[
{
"column": "ColumnA",
"value": " \"StringA\""
},
{
"column": "ColumnB",
"value": " \"StringB\""
}
],
...,
[
{
"column": "ColumnA",
"value": " \"StringA\""
},
{
"column": "ColumnB",
"value": " \"StringB\""
}
],
...
]
}
]
}
]
Every object in the columns list is a HashSet of ColumnValues, a class I created and is defined the following way:
public class ColumnValues
{
private string column;
private string value;
public ColumnValues(string col, string val)
{
column = col;
value = val;
}
public string Column
{
get {return column;}
}
public string Value
{
get {return value;}
}
public override bool Equals(object obj)
{
return obj is ColumnValues values &&
column == values.column &&
value == values.value &&
Column == values.Column &&
Value == values.Value;
}
public override int GetHashCode()
{
return HashCode.Combine(column, value, Column, Value);
}
}
So far, so good. However the issue is that in columns, I'm having duplicates of lists. columns is a field in DataModel, another class:
public class DataModel
{
private string entity;
private List<HashSet<ColumnValues>> columns;
private string rule;
public DataModel(string entityName, List<HashSet<ColumnValues>> columnList)
{
entity = entityName;
columns = columnList;
}
public string Entity
{
get { return entity; }
}
public List<HashSet<ColumnValues>> Columns
{
get { return columns; }
set { columns = value; }
}
public string Rule
{
set { rule = value; }
}
}
I'm not understanding why the Set is allowing the existence of duplicates.
I do add that I'm returning the columns list after applying Distinct().ToList():
var dataModels = new List<DataModel>();
GatherColumns(code.Syntax);
dataModels.ForEach(dataModel => dataModel.Columns = dataModel.Columns.Distinct().ToList());
return dataModels;
TIA!
EDIT:
As per Tim's comment, I've provided the override methods Equals and GetHashCode.
I've also decided to define Columns in DataModel as a List of HashSets.
However, unfortunately the result hasn't changed.
EDIT N°2:
I've decided to create a class implementing the IEqualityComparer interface. However, little effect so far:
public class ColumnValuesComparer : IEqualityComparer<HashSet<ColumnValues>>
{
public bool Equals(HashSet<ColumnValues> c1, HashSet<ColumnValues> c2)
{
return c1.Equals(c2);
}
public int GetHashCode(HashSet<ColumnValues> obj)
{
return obj.GetHashCode();
}
}
Used here:
var dataModels = new List<DataModel>();
GatherColumns(code.Syntax);
ColumnValuesComparer comparer = new ColumnValuesComparer();
dataModels.ForEach(dataModel => dataModel.Columns = dataModel.Columns.Distinct(comparer).ToList());
return dataModels;
At this point I'm pretty much stuck, and don't know where to go moving forward.
After a bit of searching a documentation, I fell upon the concept of SetComparer.
They allow me to create objects that evaluate deep nested equality within HashSets.
So, when I try to create my HashSet of HashSets, I must pass that method:
var set = new HashSet<HashSet<ColumnValues>>(HashSet<ColumnValues>.CreateSetComparer());
set.Add(columnValues);
Related
I use FastMember to get values out of objects and nested objects. If a property is a string or int everything works fine. But now I want to get the values also for collections. Here is my code so far:
// Set accessor
var sourceAccessor = ObjectAccessor.Create(source);
if (sourceAccessor.Target.GetType().GetInterface(nameof(ICollection)) != null || sourceAccessor.Target.GetType().GetInterface(nameof(IEnumerable)) != null)
{
foreach (/* idk */)
{
// READ & RETURN VALUES HERE
}
}
An object could look like this:
{
Id: 1,
Surname: Doe,
Prename: John,
Professions: [
{ Name: ab },
{ Name: xy }
]
}
Which means professions would result in a problem.
Any advise how I can solve this problem? Thanks!
It's not obvious from the question what the data type of the source variable is, but you should just be able to check if the value returned by the accessor implements IEnumerable or not and act accordingly.
Here's a quick worked example that iterates over the Professions property of a 'Person' object and just dumps the ToString() representation to the console - if you wanted to dive into each Profession object using FastMember you could construct another ObjectAccessor to do it, I guess - it's not clear what your goal is once you're iterating.
The same tactic will work if you're building the ObjectAccessor directly from an array - you just check if the accessor.Target is IEnumerable and cast-and-iterate in a similar fashion.
class Program
{
static void Main(string[] args)
{
var p = new Person
{
Professions = new List<Profession>
{
new Profession("Joker"),
new Profession("Smoker"),
new Profession("Midnight toker")
}
};
var accessor = ObjectAccessor.Create(p);
var professions = accessor[nameof(Person.Professions)];
if (professions is IEnumerable)
{
foreach (var profession in (IEnumerable)professions)
{
Console.WriteLine(profession);
}
}
}
}
class Person
{
public List<Profession> Professions { get; set; }
}
class Profession
{
public string Name { get; set; }
public Profession( string name)
{
Name = name;
}
public override string ToString()
{
return Name;
}
}
I hope someone can help me to understand how I can update a document in a mongodb.
My problem is that i have a document which contains an array. And in this array there are objects with a specific ID(like you would find in sql database). Now I want to update the data inside those objects if they have the searched id.
A document looks like this
{
"_id": "63dafa72f21d48312d8ca405",
"tasks": [{
"_ref": "63d8d8d01beb0b606314e322",
"data": {
"values": [{
"key": "Deadline",
"value": "2014-10-13"
}]
}
}, {
"_ref": "84dd046c6695e32322d842f5",
"data": {
"values": []
}
}]
}
I did write the method updateProject
public bool updateProject(Project pro, Project dbPro)
{
var collection = db.GetCollection<BsonDocument>("projects");
var filter = Builders<BsonDocument>.Filter.Eq("_id", dbPro.Id);
var update = Builders<BsonDocument>.Update.Set("tasks", pro.Tasks);
var result = collection.UpdateOne(filter, update);
if (result.IsModifiedCountAvailable)
{
if (result.ModifiedCount == 1)
{
return true;
}
}
return false;
}
And thats how a project does look like in c#.
class Project{
public string id;
public List<Task> Tasks;
}
class Task{
public string id;
public List<Value> Values;
}
class Value{
public String key;
public String value;
}
but i cant figure out how i can go deeper to find the searched id.
I have an application that serializes a list of objects to json, then sends this over a socket connection to a client.
On the client side, I'm using JsonConvert.PopulateObject() to populate an existing list of objects with the newly received json data. However, the objects are continually being appended to the list instead of reusing the existing objects in the list if there are any duplicates.
Here is the class I'm serializing/deserializing:
public class Process : INotifyPropertyChanged
{
private int _id;
private string _name;
public int ID
{
get { return _id; }
set
{
if (value != _id)
{
_id = value;
NotifyPropertyChanged("ID");
}
}
}
public string Name
{
get { return _name; }
set
{
if (value != _name)
{
_name = value;
NotifyPropertyChanged("Name");
}
}
}
public Process() { }
public Process(int id, string name)
{
ID = id;
Name = name;
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Here is the PopulateObject code I'm using:
JsonSerializerSettings settings = new JsonSerializerSettings() { PreserveReferencesHandling = PreserveReferencesHandling.Objects, ObjectCreationHandling = ObjectCreationHandling.Auto };
ObservableCollection<Process> Processes = new ObservableCollection<Process>();
JsonConvert.PopulateObject(response, Processes, settings);
It seems like json.net just doesn't know an object is a duplicate reference despite the property values being exactly the same. I've tried multiple combinations of the JsonObject attribute on my class (IsReference = true, Id = "ID"), etc. I cannot seem to get json to recognize two objects are the same if their ID property is matching.
Thats not what PreserveReferencesHandling does. It is used to avoid serializing duplicate objects, effectively shortening the json result. Example:
List<NameValuePair> nvpList = new List<NameValuePair>();
NameValuePair z = new NameValuePair(Name="Ziggy", Value= 42);
nvpList.Add(z);
nvpList.Add(new NameValuePair("Zoey", 3));
nvpList.Add(z);
JsonSerializerSettings settings = new JsonSerializerSettings() {
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
};
string json = JsonConvert.SerializeObject(nvpList, Formatting.Indented,
settings);
My List has 2 Ziggy objects, but the resulting json is:
[
{
"$id": "1",
"Name": "Ziggy",
"Value": 42
},
{
"$id": "2",
"Name": "Zoey",
"Value": 3
},
{
"$ref": "1"
}
]
It assigns an internal $Id and then references that for the duplicate object. This only applies where the object references are the same. If 2 Ziggy objects had been created and added - even with the same values - the json would reflect that and duplicate them.
To prevent duplicates in the list when deserializing, you will have to use a mapper or the equivalent code:
List<NameValuePair> tmp = JsonConvert.DeserializeObject<List<NameValuePair>>(json);
foreach (NameValuePair nvp in tmp)
{
if (nvpList.Where(w => w.Value == nvp.Value).FirstOrDefault() == null)
{
nvpList.Add(nvp);
}
}
This adds just those where the Value/Id does not already exist in the master list, add whatever logic you need to detect dupes.
See: Preserving Object References
Have your tried overriding the Equals() function of the serilized object
public override bool Equals(Process p)
{
// If parameter is null return false:
if ((object)p == null)
{
return false;
}
// Return true if the fields match:
return (ID == p.ID);
}
I'm new in this pattern , could please someone help me in it?
I got an Object like this :
public class Object
{
public string Name { get; set; }
public object Value { get; set; }
public List<Object> Childs { get; set; }
}
Here is an JSON example:
{
"Name": "Method",
"Value": "And",
"Childs": [{
"Name": "Method",
"Value": "And",
"Childs": [{
"Name": "Operator",
"Value": "IsEqual",
"Childs": [{
"Name": "Name",
"Value": "5",
"Childs": []
}]
},
{
"Name": "Operator",
"Value": "IsEqual",
"Childs": [{
"Name": "Name",
"Value": "6",
"Childs": []
}]
}]
},
{
"Name": "Operator",
"Value": "IsEqual",
"Childs": [{
"Name": "Name",
"Value": "3",
"Childs": []
}]
}]
}
My question how to make Visitor Pattern in order to get this final string:
(Name IsEqual 3)And((Name IsEqul 5)And(Name IsEqual 6))
To implement visitor pattern you need two simple interfaces
IVisitable with an Accept method having the IVisitor as the parameter.
IVisitor with many Visit methods for each implementation of IVisitable
So basic idea of the visitor pattern is to change the behavior dynamically according to the type of implementation.
For your case the thing you want to visit (the visitable) is the Object class which apparently does not have different derivatives and you want to change the behavior according to a property value not the type. So Visitor Pattern is not what you really need here and I highly recommend you to consider the answers with the recursive method.
But if you really want to use visitor pattern here, it may look something like this.
interface IVisitable { void Accept(IVisitor visitor); }
interface IVisitor {
void VisitAnd(Object obj);
void VisitEquals(Object obj);
}
Since the Object class is a simple POCO I assume you won't want to implement an interface and add a method into this class. So you'll need an adapter object which adapts Object to IVisitable
class VisitableObject : IVisitable {
private Object _obj;
public VisitableObject(Object obj) { _obj = obj; }
public void Accept(IVisitor visitor) {
// These ugly if-else are sign that visitor pattern is not right for your model or you need to revise your model.
if (_obj.Name == "Method" && _obj.Value == "And") {
visitor.VisitAnd(obj);
}
else if (_obj.Name == "Method" && _obj.Value == "IsEqual") {
visitor.VisitEquals(obj);
}
else
throw new NotSupportedException();
}
}
}
public static ObjectExt {
public static IVisitable AsVisitable(this Object obj) {
return new VisitableObject(obj);
}
}
And finally the visitor implementation may look like this
class ObjectVisitor : IVisitor {
private StringBuilder sb = new StringBuilder();
public void VisitAnd(Object obj) {
sb.Append("(");
var and = "";
foreach (var child in obj.Children) {
sb.Append(and);
child.AsVisitable().Accept(this);
and = "and";
}
sb.Append(")");
}
public void VisitEquals(Object obj) {
// Assuming equal object must have exactly one child
// Which again is a sign that visitor pattern is not bla bla...
sb.Append("(")
.Append(obj.Children[0].Name);
.Append(" Equals ");
.Append(obj.Children[0].Value);
.Append(")");
}
}
The JSON clearly represents a token tree (possibly produced by a parser).
Visitor pattern use polymorphism.
In order to be used by a Visitor pattern, you must deserialize it to obtain objects with the different Visit behavior :
MethodToken
OperatorToken
NameToken
Then IVisitor should implement Visit method for each:
public interface IVisitor
{
void Visit(MethodToken token) { /* */ }
void Visit(OperatorToken token) { /* */ }
void Visit(NameToken token) { /* */ }
}
public interface IVisitable
{
void Accept(IVisitor visitor);
}
public class MethodToken : IVisitable
{
public void Accept(IVisitor visitor)
{
visitor.Visit(this);
}
}
Additional remark:
Object is a really poor name especially in C# as Object is the base class for every classes, not to mention the conflict, it doesn't convey any special meaning ... What about token ?
public class Token
{
public string Name { get; set; }
public string Value { get; set; }
public List<Token> Children { get; set; }
}
About property Childs...
Purpose of Visitor
You shouldn't use a screwdriver if you don't know when/why to use it (by the way it can be dangerous).
Visitor pattern is useful to avoid 'ugly'/hard to maintain/painful to read dozen switch cases or the even worse if else if else while giving you the strong type checking advantage. It also helps to keep related code (high cohesion) in one class (the Visitor). Of course, once implemented, the tree of objects (here tokens) can be visited by several kind of visitors as long as they implement the IVisitor interface.
In your case, you must first convert each Token to a strongly subtype of Token (through Dictionary mapping to avoid any if/switch or custom deserialization)
In your case:
First read the text (obviously it's json format) and transform it to an object. We usually call this deserialization. It's possible here because the text is already formatted with a well-known correct structured format for which it is easy to find a lexer/parser. (Otherwise you would have to write your own lexer/parser or use something like lex/yacc).
However, we have to partial deserialize each part of the text to the right type.
We will use Newtonsoft.Json to do this:
// We define a base class abstract (it cannot be instantiated and we can enforce implementation of methods like the Accept()
public abstract class BaseToken : IVisitable
{
public string Value { get; set; }
public List<BaseToken> Children { get; } = new List<BaseToken>();
public abstract void Accept(IVisitor visitor);
}
Read the text and parse Json:
// Load text in memory
var text = File.ReadAllText("path/to/my/file.json");
// Get Token instance
var jsonToken = JObject.Parse(text);
We must process JToken to extract the right class instances:
// Get the strong typed tree of token
var token = CreateToken(jsonToken);
CreateToken method:
private static BaseToken CreateToken(JToken jsonToken)
{
var typeOfToken = jsonToken["Name"];
if (typeOfToken == null || typeOfToken.Type != JTokenType.String)
{
return null;
}
BaseToken result;
switch (typeOfToken.ToString())
{
case "Method":
{
result = jsonToken.ToObject<MethodToken>();
break;
}
case "Operator":
{
result = jsonToken.ToObject<OperatorToken>();
break;
}
default:
{
result = jsonToken.ToObject<NameToken>();
break;
}
}
var jChildrenToken = jsonToken["Childs"];
if (result != null &&
jChildrenToken != null &&
jChildrenToken.Type == JTokenType.Array)
{
var children = jChildrenToken.AsJEnumerable();
foreach (var child in children)
{
var childToken = CreateToken(child);
if (childToken != null)
{
result.Children.Add(childToken);
}
}
}
return result;
}
As you can see there are still some switch pattern on text.
Then call the token visitor:
// Create the visitor
var tokenVisitor = new TokenVisitor();
// Visit the tree with visitor
token.Accept(tokenVisitor);
// Output the result
Console.WriteLine(tokenVisitor.Output);
Code of TokenVisitor
internal class TokenVisitor : IVisitor
{
private readonly StringBuilder _builder = new StringBuilder();
// invert the order of children first
private int firstIndex = 1;
private int secondIndex = 0;
// Keep track of name tokens
private readonly HashSet<BaseToken> _visitedTokens = new HashSet<BaseToken>();
public string Output => _builder.ToString();
public void Visit(MethodToken token)
{
// Store local to avoid recursive call;
var localFirst = firstIndex;
var localSecond = secondIndex;
// back to normal order of children
firstIndex = 0;
secondIndex = 1;
RenderChild(token.Children, localFirst);
_builder.Append(token.Value);
RenderChild(token.Children, localSecond);
}
private void RenderChild(List<BaseToken> children, int index)
{
if (children.Count > index)
{
_builder.Append("(");
children[index].Accept(this);
_builder.Append(")");
}
}
public void Visit(OperatorToken token)
{
if (token.Children.Count > 0)
{
token.Children[0].Accept(this);
_builder.Append(" ");
}
_builder.Append(token.Value);
if (token.Children.Count > 0)
{
_builder.Append(" ");
token.Children[0].Accept(this);
}
}
public void Visit(NameToken token)
{
if (_visitedTokens.Contains(token))
{
_builder.Append(token.Value);
}
else
{
_visitedTokens.Add(token);
_builder.Append(token.Name);
}
}
}
The above implementation seeks to cope with your expectations(ie output exactly the expected string). It may not be bulletproof. You can find the full code on GitHub
First of all you have wrong order in the result.Second, somethimes you miss brackets in the result.Final it should be:
(((Name IsEqual 5) And (Name IsEqual 6)) And (Name IsEqual 3))
To complete this task you should use recursive function.
static IEnumerable<string> ReturnString(Obj val)
{
foreach (Obj node in val.Childs)
yield return ConvertToString(node);
}
static string ConvertToString(Obj val)
{
switch(val.Name)
{
case "Operator":
{
return string.Format("({0} {1} {2})", val.Childs[0].Name, val.Value, val.Childs[0].Value);
}
case "Method":
{
IEnumerable<string> coll = ReturnString(val);
StringBuilder final = new StringBuilder();
final.Append("(");
IEnumerator<string> e = coll.GetEnumerator();
e.MoveNext();
final.Append(string.Format("{0}", e.Current, val.Value));
while (e.MoveNext())
{
final.Append(string.Format(" {0} {1}", val.Value, e.Current));
}
final.Append(")");
return final.ToString();
}
case "Name":
return Convert.ToString(val.Value);
}
return "-";
}
Below is your example in the code:
string s = ConvertToString(new Obj
{
Name = "Method",
Value = "And",
Childs = new List<Obj>
{
new Obj()
{
Name = "Method",
Value = "And",
Childs = new List<Obj>
{
new Obj()
{
Name = "Operator",
Value = "IsEqual",
Childs = new List<Obj>
{
new Obj()
{
Name="Name",
Value="5",
Childs=null
}
}
},
new Obj()
{
Name = "Operator",
Value = "IsEqual",
Childs = new List<Obj>
{
new Obj()
{
Name="Name",
Value="6",
Childs=null
}
}
}
}
},
new Obj()
{
Name = "Operator",
Value = "IsEqual",
Childs = new List<Obj>
{
new Obj()
{
Name="Name",
Value="3",
Childs=null
}
}
}
}
});
This might not be what you want. But one way to create the output that you want without using the Visitor pattern is add the following method to the Object class, like this:
public string Format()
{
if (Name == "Operator")
{
if(Childs == null || Childs.Count != 1)
throw new Exception("Invalid Childs");
Object chlid = Childs[0];
return chlid.Name + " IsEqual " + chlid.Value;
}
if (Name == "Method")
{
if(Childs == null || Childs.Count == 0)
throw new Exception("Invalid Childs");
var str = " " + Value + " ";
return string.Join(str, Childs.Select(x => "(" + x.Format() + ")"));
}
throw new Exception("Format should only be invoked on Operator/Method");
}
How do I find and replace a property using Linq in this specific scenario below:
public interface IPropertyBag { }
public class PropertyBag : IPropertyBag
{
public Property[] Properties { get; set; }
public Property this[string name]
{
get { return Properties.Where((e) => e.Name == name).Single(); }
//TODO: Just copying values... Find out how to find the index and replace the value
set { Properties.Where((e) => e.Name == name).Single().Value = value.Value; }
}
}
Thanks for helping out in advance.
Do not use LINQ because it will not improve the code because LINQ is designed to query collection and not to modify them. I suggest the following.
// Just realized that Array.IndexOf() is a static method unlike
// List.IndexOf() that is an instance method.
Int32 index = Array.IndexOf(this.Properties, name);
if (index != -1)
{
this.Properties[index] = value;
}
else
{
throw new ArgumentOutOfRangeException();
}
Why are Array.Sort() and Array.IndexOf() methods static?
Further I suggest not to use an array. Consider using IDictionary<String, Property>. This simplifies the code to the following.
this.Properties[name] = value;
Note that neither solution is thread safe.
An ad hoc LINQ solution - you see, you should not use it because the whole array will be replaced with a new one.
this.Properties = Enumerable.Union(
this.Properties.Where(p => p.Name != name),
Enumerable.Repeat(value, 1)).
ToArray();
[note: this answer was due to a misunderstanding of the question - see the comments on this answer. Apparently, I'm a little dense :(]
Is your 'Property' a class or a struct?
This test passes for me:
public class Property
{
public string Name { get; set; }
public string Value { get; set; }
}
public interface IPropertyBag { }
public class PropertyBag : IPropertyBag
{
public Property[] Properties { get; set; }
public Property this[string name]
{
get { return Properties.Where((e) => e.Name == name).Single(); }
set { Properties.Where((e) => e.Name == name).Single().Value = value.Value; }
}
}
[TestMethod]
public void TestMethod1()
{
var pb = new PropertyBag() { Properties = new Property[] { new Property { Name = "X", Value = "Y" } } };
Assert.AreEqual("Y", pb["X"].Value);
pb["X"] = new Property { Name = "X", Value = "Z" };
Assert.AreEqual("Z", pb["X"].Value);
}
I have to wonder why the getter returns a 'Property' instead of whatever datatype .Value, but I'm still curious why you're seeing a different result than what I am.