How can I get only values when I use a JsonConvert.SerializeObject? I don't need repeat words like id, name, etc...
Example:{ id: 189, name:'Paul', age:31, } x { [189, 'Paul', 31] }
Thanks!
I need to use with PageList class
public class PageList {
IEnumerable _rows;
int _total;
int _page;
int _records;
object _userData;
public PageList(IEnumerable rows, int page, int total, int records, object userData) {
_rows = rows;
_page = page;
_total = total;
_records = records;
_userData = userData;
}
public PageList(IEnumerable rows, int page, int total, int records)
: this(rows, page, total, records, null) {
}
public int total { get { return _total; } }
public int page { get { return _page; } }
public int records { get { return _records; } }
public IEnumerable rows { get { return _rows; } }
[JsonIgnore]
public object userData { get { return _userData; } }
public override string ToString() {
return Newtonsoft.Json.JsonConvert.SerializeObject(this, new IsoDateTimeConverter() { DateTimeFormat = "dd-MM-yyyy hh:mm:ss" });
}
}
The closest thing I can think of is
var yourObjectList = List<YourObject>(){.....}
string s = JsonConvert.SerializeObject(GetObjectArray(yourObjectList));
public static IEnumerable<object> GetObjectArray<T>(IEnumerable<T> obj)
{
return obj.Select(o => o.GetType().GetProperties().Select(p => p.GetValue(o, null)));
}
The second one is not valid JSON ( { 189, 'Paul', 31 } ). Maybe you want an array instead ([ 189, 'Paul', 31 ]), in which case you can instead of using the serializer directly, first load the object into a JObject, then take only its values.
public class Foo
{
public int id;
public string name;
public int age;
}
public class Test
{
public static void Main()
{
Foo foo = new Foo { id = 189, name = "Paul", age = 31 };
JObject jo = JObject.FromObject(foo);
JArray ja = new JArray();
foreach (var value in jo.Values())
{
ja.Add(value);
}
Console.WriteLine(ja);
}
}
Or if you really want the non-JSON format, you can also use the JObject enumeration and print the values yourself.
Related
I'm coding a simple console app as below and I'm getting the following error:
'SortedList<int, Employee>' does not contain a definition for 'CopyTo' and no accessible extension method 'CopyTo' accepting a first argument of type 'SortedList<int, Employee>'
This is in the getAllEmployeesistAll() method. AS part of the assignment, the method must return an Employee[] return type, hence the need to cast.
Appreciate any help!
Link to docs: https://learn.microsoft.com/en-us/dotnet/api/system.collections.sortedlist.copyto?view=net-6.0
When I put in a second argument (for the index start), I get an error saying no overload 2 arguments.
using System.Collections;
using System;
namespace Collections
{
public class Employee
{
private string employeeName;
private int employeeId;
private double salary;
public string EmployeeName
{
get { return employeeName; }
set { employeeName = value; }
}
public int EmployeeId
{
get { return employeeId; }
set { employeeId = value; }
}
public double Salary
{
get { return salary; }
set { salary = value; }
}
}
public class EmployeeDAL
{
SortedList<int, Employee> employees = new SortedList<int, Employee>();
public bool AddEmployee(Employee e)
{
try
{
employees.Add(e.EmployeeId, e);
return true;
}
catch
{
return false;
}
}
public bool DeleteEmployee(int id)
{
try
{
employees.RemoveAt(id - 1);
return true;
}
catch
{
return false;
}
}
public string SearchEmployee(int id)
{
var employee = employees[id - 1];
return $"You have searched for: Employee ID #{employee.EmployeeId} - Name: {employee.EmployeeName}\nSalary: S${employee.Salary}";
}
public Employee[] GetAllEmployeesistAll()
{
Employee[] employeeArr = new Employee[employees.Count];
employees.CopyTo(employeeArr);
foreach (Employee e in employeeArr)
Console.WriteLine($"Employee ID {e.EmployeeId}: {e.EmployeeName}, salary: S${e.Salary}");
return employeeArr;
}
}
public class Program
{
public static void Main(string[] args)
{
Employee ash = new Employee();
ash.EmployeeName = "Ash";
ash.EmployeeId = 1;
ash.Salary = 100000;
Employee lucy = new Employee();
lucy.EmployeeName = "Lucy";
lucy.EmployeeId = 2;
lucy.Salary = 200000;
EmployeeDAL employeeDAL = new EmployeeDAL();
employeeDAL.AddEmployee(ash);
employeeDAL.AddEmployee(lucy);
Console.WriteLine(employeeDAL.SearchEmployee(1));
//employeeDAL.DeleteEmployee(2);
employeeDAL.GetAllEmployeesistAll();
}
}
}
The link in the question go to the class ListedSorted, but the error is about the class ListedSorted<TKey, TValue>.
See this documentation, the class ListedSorted<TKey, TValue> don't have a method CopyTo.
To convert ListedSorted<TKey, TValue> in TValue[], you can use LINQ method ToArray :
var employees = new SortedList<int, Employee>();
var employeesArray = employees.Values.ToArray();
I'm coding a func that inputs an array with different year of birth and prints out the oldest person.
I'm trying to add a validation with get and set but my syntax is wrong.
enter image description here
TL;DR
Properties declaration part:
public class Employee
{
private string _fullName;
private int _yearIn;
public string FullName
{
get => _fullName;
set
{
if (!string.IsNullOrEmpty(value))
{
_fullName = value;
}
}
}
public int YearIn
{
get => _yearIn;
set
{
if (value > 0 && value <= 2020)
{
_yearIn = YearIn;
}
}
}
}
And a usage:
var employees = new List<Employee>();
for (int i = 0; i < 3; i++)
{
Console.WriteLine("Enter Name:");
string name = Console.ReadLine();
Console.WriteLine("Enter Year:");
int yearIn = Convert.ToInt32(Console.ReadLine());
employees.Add(new Employee
{
FullName = name,
YearIn = yearIn
});
}
Update
You can do the same in a bit different manner though:
public class Employee
{
private string _fullName;
private int _yearIn;
public bool IsNameValid { get; set; }
public bool IsYearValid { get; set; }
public string FullName
{
get => _fullName;
set
{
_fullName = value;
IsNameValid = string.IsNullOrEmpty(value);
}
}
public int YearIn
{
get => _yearIn;
set
{
_yearIn = value;
IsYearValid = (value < 0) || (value > 2020);
}
}
}
And later:
Console.WriteLine($"Employee name is: {employees[i].IsNameValid}");
Console.WriteLine($"Employee year is: {employees[i].IsYearValid}");
Update 2
And the last alternative version is that you can use Validation attributes:
public class Employee
{
[Required]
[Range(0, 2020)]
public int YearIn { get; set; }
[Required]
[StringLength(50)]
public string FullName { get; set; }
}
later:
var empl = new Employee{ YearIn = yearIn, FullName = name};
var context = new ValidationContext(empl, serviceProvider: null, items: null);
var results = new List<ValidationResult>();
var isValid = Validator.TryValidateObject(empl, context, results, true);
Console.WriteLine($"Is model valid: {isValid}");
if (isValid)
{
employees.Add(new Employee
{
FullName = name,
YearIn = yearIn
});
}
You can create wrapper classes over array and use indexer method for accessing the array item.
There in, you can put all your validation logic.
class IntData
{
public IntData(int size)
{
data = new int[size];
}
// Array of temperature values
private int[] data;
public int this[int index]
{
get
{
return data[index];
}
set
{
// Do your validation here
if (value < 5000)
{
data[index] = value;
}
}
}
}
static void Main(string[] args)
{
IntData year = new IntData(3);
year[0] = 2000;
year[1] = 6000; // This value won't set because of validation
year[2] = 4000;
Console.Read();
}
I'm trying to randomly select one of the customer items from the list. I am not sure what to do to actually print out the info within the list.
I have this as my customer class
namespace PizzaParlor
{
class Customer
{
private string name;
private int flavor;
private int price;
private int quality;
private int speed;
private int accessibility;
private int brand;
private int convenience;
private int variety;
public Customer(string name, int flavor, int price, int quality, int speed, int accessibility, int brand, int convenience, int variety)
{
this.name = name;
this.flavor = flavor;
this.price = price;
this.quality = quality;
this.speed = speed;
this.accessibility = accessibility;
this.brand = brand;
this.convenience = convenience;
this.variety = variety;
}
// Name, Speed, Quality, Variety, Convenience, Accessibility, price, brand, flavor
public string Name
{
get { return name; }
set { name = value; }
}
public int Speed
{
get { return speed; }
set { speed = value; }
}
public int Quality
{
get { return quality; }
set { quality = value; }
}
public int Variety
{
get { return variety; }
set { variety = value; }
}
public int Convenience
{
get { return convenience; }
set { convenience = value; }
}
public int Accessibility
{
get { return accessibility; }
set { accessibility = value; }
}
public int Price
{
get { return price; }
set { price = value; }
}
public int Brand
{
get { return brand; }
set { brand = value; }
}
public int Flavor
{
get { return flavor; }
set { flavor = value; }
}
}
}
and this as my main class that I set up to work with the customer class:
namespace PizzaParlor
{
class Program
{
static void Main(string[] args)
{
var random = new Random();
List<Customer> CustomerList = new List<Customer>();
CustomerList.Add(new Customer("bill", 20,15,10,5,10,20,5,15));
CustomerList.Add(new Customer("kevin", 15, 10, 5, 20, 15, 15, 0, 20));
CustomerList.Add(new Customer("clair", 8,25,2,25,5,15,0,20));
CustomerList.Add(new Customer("jim", 15,20,10,15,0,40,0,0));
CustomerList.Add(new Customer("rachel", 20,15,10,5,10,30,0,10));
CustomerList.Add(new Customer("jeff", 30,20,5,5,10,10,0,20));
CustomerList.Add(new Customer("Mike", 21,23,0,10,14,16,0,16));
CustomerList.Add(new Customer("john", 25,15,10,10,10,5,5,20));
int index = random.Next(CustomerList.Count);
Console.WriteLine(CustomerList[index]);
}
}
}
I know that the random.Next(CustomerList.Count) will randomly a select from the list but I don't know why it is returning this output:
This is because the when you attempt to print an object (e.g. Customer, the default implementation of ToString() is executed. This produces the output that you see.
There are 2 ways of fixing it
Print explicit fields you're interested in
int index = random.Next(CustomerList.Count);
var customer = CustomerList[index];
Console.WriteLine($"customer name = {customer.Name}, flavour = {customer.Flavour}}");
Override the ToString implementation
class Customer
{
//...
// Existing code
// ..
public override string ToString ()
{
return $"customer name = {customer.Name}, flavour = {customer.Flavour}}";
}
}
In your main method
int index = random.Next(CustomerList.Count);
var customer = CustomerList[index];
Console.WriteLine(customer);
You can use Reflection to achieve this.
foreach (var prop in typeof(Customer).GetProperties())
{
Console.WriteLine("{0}={1}", prop.Name, prop.GetValue(CustomerList[index]));
}
I'm working on an approach to have a collection that efficiently can search based on more than one property. The sample code of the approach:
class SampleCollection
{
Dictionary<Sample, Sample> _dictItems;
public SampleCollection()
{
_dictItems = new Dictionary<Sample, Sample>(new SampleEqualityComparer());
}
public Sample FindById(int id)
{
return _dictItems[new Sample(id, string.Empty)];
}
public Sample FindByName(string name)
{
return _dictItems[new Sample(-1, name)];
}
}
class Sample
{
public Sample(int id, string name)
{
Id = id;
Name = name;
}
public int Id { get; set; }
public string Name { get; set; }
public string ALotOfOtherProperties { get; set; }
}
class SampleEqualityComparer : IEqualityComparer<Sample>
{
public bool Equals(Sample x, Sample y)
{
if (x.Id >= 0 && y.Id >= 0)
{
return x.Id == y.Id;
}
return x.Name.Equals(y.Name, StringComparison.CurrentCultureIgnoreCase);
}
public int GetHashCode(Sample obj)
{
//try with only name now
return obj.Name.GetHashCode();
//return 0;
}
}
This approach works perfectly fine as long as the Name property is not modified. Understandably, the Hash value no longer matches the original item in the Dictionary when the Name is modified.
Is it possible to force the Dictionary to recalculate the hash of its keys or any other workaround if it is not possible directly.?
It is really a performance hit when using a custom class as a key. The handling can take a 10 times longer.
I suggest that you have a dictionary for name and one for id.
I recommend that you set your Name and Id setter to private like:public string Name { get; private set; }
class SampleCollection
{
public SampleCollection()
{
NameLookup = new Dictionary<string, List<Sample>>();
IdLookup = new Dictionary<int, Sample>();
}
private Dictionary<string, List<Sample>> NameLookup;
private Dictionary<int, Sample> IdLookup;
public void Add(Sample sample)
{
IdLookup.Add(sample.Id, Sample);
List<Sample> list;
if (!NameLookup.TryGetValue(sample.Name, out list))
NameLookup.Add(sample.Name, list = new List<Sample>());
list.Add(Sample);
}
public Sample FindById(int id)
{
Sample result;
IdLookup.TryGetValue(id, out result);
return result;
}
public IEnumerable<Sample> FindByName(string name)
{
List<Sample> list;
if (NameLookup.TryGetValue(name, out list))
foreach(var sample in list)
yield return sample;
}
}
I have a program that writes a huge DataTable (2.000.000 to 70.000.000 rows, depends on the configuration) to a database using a SqlBulkCopy.
I decided to change the loop that populates this table into a IDataReader, because the amount of rows often causes an OutOfMemoryException.
The table is populated like this
// int[] firsts;
// string[] seconds;
// byte[] thirds;
var table = new DataTable();
foreach(var f in firsts)
{
foreach(var s in seconds)
{
foreach(var t in thirds)
{
var row = table.NewRow();
row[0] = f;
row[1] = s;
row[2] = t;
table.Rows.Add(row);
}
}
// here I also bulk load the table and clear it
}
so in my IDataReader class I will loop by index. This is my attempt.
class TableReader : IDataReader
{
bool Eof = false;
int FirstIndex;
int SecondIndex;
int ThirdIndex;
//those are populated via constructor
int[] firsts;
string[] seconds;
byte[] thirds;
// this will be retrieved automatically via indexer
object[] Values;
public bool Read()
{
if(ThirdIndex != thirds.Length
&& SecondIndex < seconds.Length
&& FirstIndex < firsts.Length)
{
Values[0] = firsts[FirstIndex];
Values[1] = seconds[SecondIndex];
Values[2] = thirds[ThirdIndex++];
}
else if(SecondIndex != seconds.Length)
{
ThirdIndex = 0;
SecondIndex++;
}
else if(FirstIndex != firsts.Length)
{
SecondIndex = 0;
FirstIndex++;
}
else
{
Eof = true;
}
return !Eof;
}
}
I've created this code using a while(true) loop with a break instead of the Eof, but I can't seem to figure out how to do this.
Anyone can help?
This is actually possible if you implement IDataReader and use the "yield return" keyword to provide rows. IDataReader is a bit of a pain to implement, but it isn't complex at all. The code below can be adapted to load a terabyte worth of data to the database and never run out of memory.
I replaced the DataRow objects with a single object array that is reused throughout the data read.
Because there's no DataTable object to represent the columns, I had to do this myself by storing the data types and column names separately.
class TestDataReader : IDataReader {
int[] firsts = { 1, 2, 3, 4 };
string[] seconds = { "abc", "def", "ghi" };
byte[] thirds = { 0x30, 0x31, 0x32 };
// The data types of each column.
Type[] dataTypes = { typeof(int), typeof(string), typeof(byte) };
// The names of each column.
string[] names = { "firsts", "seconds", "thirds" };
// This function uses coroutines to turn the "push" approach into a "pull" approach.
private IEnumerable<object[]> GetRows() {
// Just re-use the same array.
object[] row = new object[3];
foreach (var f in firsts) {
foreach (var s in seconds) {
foreach (var t in thirds) {
row[0] = f;
row[1] = s;
row[2] = t;
yield return row;
}
}
// here I also bulk load he table and clear it
}
}
// Everything below basically wraps this.
IEnumerator<object[]> rowProvider;
public TestDataReader() {
rowProvider = GetRows().GetEnumerator();
}
public object this[int i] {
get {
return GetValue(i);
}
}
public object this[string name] {
get {
return GetValue(GetOrdinal(name));
}
}
public int Depth { get { return 0; } }
public int FieldCount { get { return dataTypes.Length; } }
public bool IsClosed { get { return false; } }
public int RecordsAffected { get { return 0; } }
// These don't really do anything.
public void Close() { Dispose(); }
public void Dispose() { rowProvider.Dispose(); }
public string GetDataTypeName(int i) { return dataTypes[i].Name; }
public Type GetFieldType(int i) { return dataTypes[i]; }
// These functions get basic data types.
public bool GetBoolean(int i) { return (bool) rowProvider.Current[i]; }
public byte GetByte(int i) { return (byte) rowProvider.Current[i]; }
public char GetChar(int i) { return (char) rowProvider.Current[i]; }
public DateTime GetDateTime(int i) { return (DateTime) rowProvider.Current[i]; }
public decimal GetDecimal(int i) { return (decimal) rowProvider.Current[i]; }
public double GetDouble(int i) { return (double) rowProvider.Current[i]; }
public float GetFloat(int i) { return (float) rowProvider.Current[i]; }
public Guid GetGuid(int i) { return (Guid) rowProvider.Current[i]; }
public short GetInt16(int i) { return (short) rowProvider.Current[i]; }
public int GetInt32(int i) { return (int) rowProvider.Current[i]; }
public long GetInt64(int i) { return (long) rowProvider.Current[i]; }
public string GetString(int i) { return (string) rowProvider.Current[i]; }
public object GetValue(int i) { return (object) rowProvider.Current[i]; }
public string GetName(int i) { return names[i]; }
public bool IsDBNull(int i) {
object obj = rowProvider.Current[i];
return obj == null || obj is DBNull;
}
// Looks up a field number given its name.
public int GetOrdinal(string name) {
return Array.FindIndex(names, x => x.Equals(name, StringComparison.OrdinalIgnoreCase));
}
// Populate "values" given the current row of data.
public int GetValues(object[] values) {
if (values == null) {
return 0;
} else {
int len = Math.Min(values.Length, rowProvider.Current.Length);
Array.Copy(rowProvider.Current, values, len);
return len;
}
}
// This reader only supports a single result set.
public bool NextResult() {
return false;
}
// Move to the next row.
public bool Read() {
return rowProvider.MoveNext();
}
// Don't bother implementing these in any meaningful way.
public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length) {
throw new NotImplementedException();
}
public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length) {
throw new NotImplementedException();
}
public IDataReader GetData(int i) {
throw new NotImplementedException();
}
public DataTable GetSchemaTable() {
return null;
}
}