Is there any data structure that behaves like both a Set and Map in OOP? - data-structures

Considering the following example:
class Person {
int citizenNumber; // key
int age;
string name;
constructor(citizenNumber, age, name);
}
Map<int, Person> personsMap = {};
//Map allows the inconsistency fault: key != citizenNumber (object key)
personsMap.put(1, new Person(2, 18, "John"));
// Set would allow this if search by a key was possible
Set<Person> personsSet = { new Person(1, 20, "Paul") };
int searchableCitizenNumber = 1;
// Person should implement/extend some key like `key => citizenNumber`
Person person = personsSet.get(searchableCitizenNumber);
Is there any data strucuture that:
Does not allow duplicates
Allow queries from a given key stored in the object itself

Related

Sending explicit zeroes in protobuf3

In Protobuf3 zero is the default value for numeric types, and so they are filtered out when serialized.
I have an application where I need to send a value only when it has changed. For example, x was 1, now x is 0, send this value.
It isn't possible to send only the delta, eg -1, because some of these values are floats or doubles, and we do not want to accrue errors.
There are over 200 different variables in some classes I need to serialize, so solutions like "add a boolean to flag which fields have changed" are possible but not fun. Other suggestions that have a large amount of per-field work or processing are undesirable too.
Is there a simple mechanism to tell protobuf3 to explicitly keep a value even though it is the default value?
Possible solutions:
Send the entire class each time. The main downside here is some fields may have a lot of data.
Use a boolean "has changed" in the schema to indicate if a variable has changed, even if it is 0
Use a magic value. Terrible idea, but possible. Not going to do this.
If you need to distinguish 0 and null then you can use proto3 wrapper types: https://developers.google.com/protocol-buffers/docs/reference/csharp-generated#wrapper_types
There are special wrapper types for such case: StringWrapper, Int32Wrapper and etc. All of the wrapper types that correspond to C# value types (Int32Wrapper, DoubleWrapper, BoolWrapper etc) are mapped to Nullable<T> where T is the corresponding non-nullable type.
Since you tagged protobuf-net, you can do this at the field level:
[ProtoMember(..., IsRequired = true)]
// your field
or globally (here I'm assuming you are using the default model, which is a pretty safe assumption usually):
RuntimeTypeModel.Default.ImplicitZeroDefault = false;
and you're done;
Note: if you're interested in deltas, you can also do this conditionally - for a property Foo, you can add:
private bool ShouldSerializeFoo() { /* your rules here */ }
(this is a name-based pattern used by many serializers and other tools; in some scenarios, it needs to be public, but protobuf-net is usually happy with it non-public)
As a non-trivial example of an object that tracks delta state internally:
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.IO;
static class P
{
static void Main()
{
var obj = new MyType
{
Foo = 42,
Bar = "abc",
Blap = DateTime.Now
};
ShowPayloadSize("original", obj);
obj.MarkClean();
ShowPayloadSize("clean", obj);
obj.Foo = 42;
obj.Bar = "abc";
ShowPayloadSize("set property to same", obj);
obj.Foo = 45;
obj.Bar = "new value";
ShowPayloadSize("set property to different", obj);
obj.MarkClean();
ShowPayloadSize("clean again", obj);
}
static void ShowPayloadSize<T>(string caption, T obj)
{
using var ms = new MemoryStream();
Serializer.Serialize(ms, obj);
Console.WriteLine($"{caption}: {ms.Length} bytes");
}
}
[ProtoContract]
public class MyType
{
private int _dirty = -1; // treat everything as dirty by default
public void MarkClean() => _dirty = 0;
public bool IsDirty => _dirty != 0;
private bool ShouldSerialize(int flag) => (_dirty & flag) != 0;
private void Set<T>(ref T field, T value, int flag)
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
_dirty |= flag;
}
}
[ProtoMember(1)]
public int Foo
{
get => _foo;
set => Set(ref _foo, value, 1 << 0);
}
public bool ShouldSerializeFoo() => ShouldSerialize(1 << 0);
private int _foo;
[ProtoMember(2)]
public string Bar
{
get => _bar;
set => Set(ref _bar, value, 1 << 1);
}
public bool ShouldSerializeBar() => ShouldSerialize(1 << 1);
private string _bar;
[ProtoMember(3)]
public DateTime Blap
{
get => _blap;
set => Set(ref _blap, value, 1 << 2);
}
public bool ShouldSerializeBlap() => ShouldSerialize(1 << 2);
private DateTime _blap;
}

Java Map: group by key's attribute and max over value

I have an instance of Map<Reference, Double> the challenge is that the key objects may contain a reference to the same object, I need to return a map of the same type of the "input" but grouped by the attribute key and by retaining the max value.
I tried by using groupingBy and maxBy but I'm stuck.
private void run () {
Map<Reference, Double> vote = new HashMap<>();
Student s1 = new Student(12L);
vote.put(new Reference(s1), 66.5);
vote.put(new Reference(s1), 71.71);
Student s2 = new Student(44L);
vote.put(new Reference(s2), 59.75);
vote.put(new Reference(s2), 64.00);
// I need to have a Collection of Reference objs related to the max value of the "vote" map
Collection<Reference> maxVote = vote.entrySet().stream().collect(groupingBy(Map.Entry.<Reference, Double>comparingByKey(new Comparator<Reference>() {
#Override
public int compare(Reference r1, Reference r2) {
return r1.getObjId().compareTo(r2.getObjId());
}
}), maxBy(Comparator.comparingDouble(Map.Entry::getValue))));
}
class Reference {
private final Student student;
public Reference(Student s) {
this.student = s;
}
public Long getObjId() {
return this.student.getId();
}
}
class Student {
private final Long id;
public Student (Long id) {
this.id = id;
}
public Long getId() {
return id;
}
}
I have an error in the maxBy argument: Comparator.comparingDouble(Map.Entry::getValue) and I don't know how to fix it. Is there a way to achieve the expected result?
You can use Collectors.toMap to get the collection of Map.Entry<Reference, Double>
Collection<Map.Entry<Reference, Double>> result = vote.entrySet().stream()
.collect(Collectors.toMap( a -> a.getKey().getObjId(), Function.identity(),
BinaryOperator.maxBy(Comparator.comparingDouble(Map.Entry::getValue)))).values();
then stream over again to get List<Reference>
List<Reference> result = vote.entrySet().stream()
.collect(Collectors.toMap(a -> a.getKey().getObjId(), Function.identity(),
BinaryOperator.maxBy(Comparator.comparingDouble(Map.Entry::getValue))))
.values().stream().map(e -> e.getKey()).collect(Collectors.toList());
Using your approach of groupingBy and maxBy:
Comparator<Entry<Reference, Double>> c = Comparator.comparing(e -> e.getValue());
Map<Object, Optional<Entry<Reference, Double>>> map =
vote.entrySet().stream()
.collect(
Collectors.groupingBy
(
e -> ((Reference) e.getKey()).getObjId(),
Collectors.maxBy(c)));
// iterate to get the result (or invoke another stream)
for (Entry<Object, Optional<Entry<Reference, Double>>> obj : map.entrySet()) {
System.out.println("Student Id:" + obj.getKey() + ", " + "Max Vote:" + obj.getValue().get().getValue());
}
Output (For input in your question):
Student Id:12, Max Vote:71.71
Student Id:44, Max Vote:64.0

How do I specify the field in an object to update with a string or some other pointer c#

I'm just learning visual c# in visual studio
Ok, so I have a ton of data fields in a form, and then I want to write the handlers to all call one main method, update, which then updates a resultsEntry object, which encapsulates a bunch of uint variables with various names.
How do I write an update method to put in either the results object, or the update method that will take the name of the variable in resultsEntry as a string, and the integer to update it with, and then update that field.
Basically, I need to do a
resultsEntry.(inStringHere) = inValueHere;
where resultsEntry is the object being updated, the inStringHere specifies the field to be updated, and the inValueHere represents the integer value to assign to it.
Thanks!
Sam French
You have two challenges,
Setting a field/property in class using a string (the focus of your question). This will be accomplished using reflection.
Converting values to the type in your class (this may not be a problem for you, you may have 'typed' values. I have an ugly solution because this is not the main focus of your question.
Setting a property by name (see comments preceded with '**'):
static class Program
{
// A 'ResultEntry' type
public class ResultEntry
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
static void Main()
{
// some tuples Field1 = Property Name; Field2 = Raw Value (string)
List<Tuple<string, string>> rawEntries = new List<Tuple<string, string>>() {
new Tuple<string,string>("ID", "1")
, new Tuple<string, string>("FirstName", "George")
, new Tuple<string, string>("LastName", "Washington")
};
ResultEntry resultEntry = new ResultEntry();
// ** Get MemberInfo's for your ResultEntry. Do this once, not for each instance of ResultEntry!
MemberInfo[] members = resultEntry.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance);
// Iterate over input
foreach (var raw in rawEntries)
{
// find a MemberInfo (PropertyInfo) that matches your input 'PropertyName'
MemberInfo member = members.FirstOrDefault(m => m.MemberType == MemberTypes.Property && m.Name == raw.Item1);
if (member != null)
{
// if you input is typed you will not have to deal with
// conversion of the string to the actual type of the property
object val = raw.Item2.MyConverter(((PropertyInfo)member).PropertyType);
// ** set the value in 'ResultEntry'
((PropertyInfo)member).SetValue(resultEntry, val, null);
}
}
Console.WriteLine(string.Format("Result Entry: ID = {0}, FirstName = {1}, LastName = {2}", resultEntry.ID, resultEntry.FirstName, resultEntry.LastName));
Console.ReadLine();
}
}
If you need to deal with converting raw string input to type (e.g. string to int), then is just one strategy...
public static class Extensions
{
public static object MyConverter(this string rawValue, Type convertToMe)
{
// ugly, there are other strategies
object val;
if (convertToMe == typeof(Int32))
val = Convert.ToInt32(rawValue);
// ... add other type conversions
else
val = rawValue;
return val;
}
}
Hope this helps.

Transform list of complex objects to flatt list with LINQ

I have List of Vehicle as shown bellow. I want to show this in CSV file, so in order to do this i would like to flatten this list:
class Vehicle
{
int vid;
string name;
string desc;
CarType car;
TruckType truck;
TankType tank;
}
class CarType
{
int id;
string color;
string manual;
string model;
}
class TruckType
{
int id;
string width;
string heigh;
}
class TankType
{
int id;
string color;
string size;
}
How to get all properties (including those in the complex properties) into flat list.
How to do it with linq?
This will create an anonymous object with all the flatten fields, supposing they are public.
var flat = vehicles.Select(x => new {
vid = x.vid,
name = x.name,
desc = x.desc,
carId = x.car.id,
carColor = x.car.color;
carManual = x.car.manual;
carModel = x.car.model;
truckId = x.truck.id,
truckWidth = x.truck.width,
truckHeigh = x.truck.heigh,
tankId = x.tank.id,
tankColor = x.tank.color,
tankSize = x.tank.size
});
By the way, you should use properties and not expose the fields.

Creating ILookups

I've got an ILookup generated by some complicated expression. Let's say it's a lookup of people by last name. (In our simplistic world model, last names are unique by family)
ILookup<string, Person> families;
Now I've got two queries I'm interested in how to build.
First, how would I filter by last name?
var germanFamilies = families.Where(family => IsNameGerman(family.Key));
But here, germanFamilies is an IEnumerable<IGrouping<string, Person>>; if I call ToLookup() on it, I'd best bet would get an IGrouping<string, IGrouping<string, Person>>. If I try to be smart and call SelectMany first I'd end up with the computer doing a lot of unnecessary work. How would you convert this enumeration into a lookup easily?
Second, I'd like to get a lookups of adults only.
var adults = families.Select(family =>
new Grouping(family.Key, family.Select(person =>
person.IsAdult())));
Here I'm faced with two problems: the Grouping type doesn't exist (except as an internal inner class of Lookup), and even if it did we'd have the problem discussed above.
So, apart from implementing the ILookup and IGrouping interfaces completely, or make the computer do silly amounts of work (regrouping what has already been grouped), is there a way to alter existing ILookups to generate new ones that I missed?
(I'm going to assume you actually wanted to filter by last name, given your query.)
You can't modify any implementation of ILookup<T> that I'm aware of. It's certainly possible to implement ToLookup with an immutable lookup, as you're clearly aware :)
What you could do, however, is to change to use a Dictionary<string, List<Person>>:
var germanFamilies = families.Where(family => IsNameGerman(family.Key))
.ToDictionary(family => family.Key,
family.ToList());
That approach also works for your second query:
var adults = families.ToDictionary(family => family.Key,
family.Where(person => persion.IsAdult)
.ToList());
While that's still doing a bit more work than we might think necessary, it's not too bad.
EDIT: The discussion with Ani in the comments is worth reading. Basically, we're already going to be iterating over every person anyway - so if we assume O(1) dictionary lookup and insertion, we're actually no better in terms of time-complexity using the existing lookup than flattening:
var adults = families.SelectMany(x => x)
.Where(person => person.IsAdult)
.ToLookup(x => x.LastName);
In the first case, we could potentially use the existing grouping, like this:
// We'll have an IDictionary<string, IGrouping<string, Person>>
var germanFamilies = families.Where(family => IsNameGerman(family.Key))
.ToDictionary(family => family.Key);
That is then potentially much more efficient (if we have many people in each family) but means we're using groupings "out of context". I believe that's actually okay, but it leaves a slightly odd taste in my mouth, for some reason. As ToLookup materializes the query, it's hard to see how it could actually go wrong though...
For your first query, what about implementing your own FilteredLookup able to take advantage of coming from another ILookup ?
(thank to Jon Skeet for the hint)
public static ILookup<TKey, TElement> ToFilteredLookup<TKey, TElement>(this ILookup<TKey, TElement> lookup, Func<IGrouping<TKey, TElement>, bool> filter)
{
return new FilteredLookup<TKey, TElement>(lookup, filter);
}
With FilteredLookup class being:
internal sealed class FilteredLookup<TKey, TElement> : ILookup<TKey, TElement>
{
int count = -1;
Func<IGrouping<TKey, TElement>, bool> filter;
ILookup<TKey, TElement> lookup;
public FilteredLookup(ILookup<TKey, TElement> lookup, Func<IGrouping<TKey, TElement>, bool> filter)
{
this.filter = filter;
this.lookup = lookup;
}
public bool Contains(TKey key)
{
if (this.lookup.Contains(key))
return this.filter(this.GetGrouping(key));
return false;
}
public int Count
{
get
{
if (count >= 0)
return count;
count = this.lookup.Where(filter).Count();
return count;
}
}
public IEnumerable<TElement> this[TKey key]
{
get
{
var grp = this.GetGrouping(key);
if (!filter(grp))
throw new KeyNotFoundException();
return grp;
}
}
public IEnumerator<IGrouping<TKey, TElement>> GetEnumerator()
{
return this.lookup.Where(filter).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private IGrouping<TKey, TElement> GetGrouping(TKey key)
{
return new Grouping<TKey, TElement>(key, this.lookup[key]);
}
}
and Grouping:
internal sealed class Grouping<TKey, TElement> : IGrouping<TKey, TElement>
{
private readonly TKey key;
private readonly IEnumerable<TElement> elements;
internal Grouping(TKey key, IEnumerable<TElement> elements)
{
this.key = key;
this.elements = elements;
}
public TKey Key { get { return key; } }
public IEnumerator<TElement> GetEnumerator()
{
return elements.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
So basically your first query will be:
var germanFamilies = families.ToFilteredLookup(family => IsNameGerman(family.Key));
This allows you to avoid re-flattening-filtering-ToLookup, or creating a new dictionary (and so hashing keys again).
For the second query the idea will be similar, you should just create a similar class not filtering for the whole IGrouping but for the elements of the IGrouping.
Just an idea, maybe it could not be faster than other methods :)
The Lookup creates an index with a Key type and a value type generic indexer. You can added to a lookup and remove from a lookup by using concat for add and iterate and removing the key items in a temp list then rebuilding the lookup. The look up then works like a dictionary by retrieving the value type by a key.
public async Task TestILookup()
{
// Lookup<TKey,TElement>
List<Product> products = new List<Product>
{
new Product { ProductID = 1, Name = "Kayak", Category = "Watersports", Price = 275m },
new Product { ProductID = 2, Name = "Lifejacket", Category = "Watersports", Price = 48.95m },
new Product { ProductID = 3, Name = "Soccer Ball", Category = "Soccer", Price = 19.50m },
new Product { ProductID = 4, Name = "Corner Flag", Category = "Soccer", Price = 34.95m }
};
// create an indexer
ILookup<int, Product> lookup = (Lookup<int,Product>) products.ToLookup(p => p.ProductID, p => p);
Product newProduct = new Product { ProductID = 5, Name = "Basketball", Category = "Basketball", Price = 120.15m };
lookup = lookup.SelectMany(l => l)
.Concat(new[] { newProduct })
.ToLookup(l => l.ProductID, l=>l);
foreach (IGrouping<int, Product> packageGroup in lookup)
{
// Print the key value of the IGrouping.
output.WriteLine("ProductID Key {0}",packageGroup.Key);
// Iterate over each value in the IGrouping and print its value.
foreach (Product product in packageGroup)
output.WriteLine("Name {0}", product.Name);
}
Assert.Equal(lookup.Count(), 5);
}
public class Product
{
public int ProductID { get; set; }
public string Name { get; set; }
public string Category { get; set; }
public decimal Price { get; set; }
}
Output:
ProductID Key 1
Name Kayak
ProductID Key 2
Name Lifejacket
ProductID Key 3
Name Soccer Ball
ProductID Key 4
Name Corner Flag
ProductID Key 5
Name Basketball

Resources