In C# Convert List<dynamic> to List<string> - c#

Suppose I have a List<dynamic> object containing strings:
var dlist = new List<dynamic>()
{
"test",
"test2",
"test3"
};
Is there any efficient way of converting this into a proper List<string> object? I know I can iterate over this list and cast each element to a string, then add this to the result list, but maybe some Linq magic could do the trick in one line?
I tried using some Select() combined with ToList() and Cast<string>, but to no avail. How should this be done properly?
Note: By saying "efficient" I mean of course number of lines of code. I do not take execution time or performance into account. Also - let's suppose I do not need to type check, there will always be strings only in this dynamic list.
EDIT: Okay, so in regards to comments on "why Cast wasn't working for you" - looks like I had another problem regarding the data I receive (I'm using Dapper) and that's why it didn't work. Sorry for the confusion, I thought my list converting was wrong while the problem was not related to this.

Given
var dList = new List<dynamic>() { /*...initialize list */ };
If you are interested in extracting all the strings in the collection, ignoring all other types, you can use:
// Solution 1: Include only strings, no null values, no exceptions thrown
var strings = dlist.OfType<string>().ToList();
If you are certain that all the items in the list are strings (it will throw an exception if they are not), you can use:
// Solution 2: Include strings with null values, Exception for other data types thrown
var strings = dlist.Cast<string>().ToList();
If you want the default string representation, with null for null values, of all the items in the list, you can use:
// Solution 3: Include all, regardless of data type, no exceptions thrown
var strings = dlist.Select(item => item?.ToString()).ToList();

This answer is for dart/flutter
Given
List<dynamic> dList;
You can use
var sList = List<String>.from(dlist);
to convert a List<dynamic> to List<String>

Related

Using ternary operator inside contains in lamba expression

I have a requirement to find records that does not contain value from studentids list. There is no 1:1 matching field. The records contain 3 key fields and based on condition, I have to compare against the studentids list.
For example: If rawdata record has non empty studentnumber value, then I have to concatenate studentnumber and sequencenumber and check if that combination exists in studentids list. Otherwise, I have to concatenate EnrollNumber and SequenceNumber.
I am trying to use ternary operator inside a contains as shown below,
var studentIDs = students.Select(x => x.StudentID).Distinct().ToList();
var rawData = StudentManager.GetAllData();
var resultList = rawData.Where(x => !studentIDs.Contains($"{(!string.IsNullOrWhiteSpace(x.StudentNumber)? (x.StudentNumber+x.SequenceNumber):(x.EnrollNumber+x.SequenceNumber))}")).ToList();
However, for larger dataset (more than 5K), it seems getting slower. Any suggestion for alternate method or way to improve will be greatly appreciated. Especially, if the code (Ternary operator) inside Contains can be simplified.
As #derpischer mention on the commend, Did you try with a HashSet?
Replace the firs line for the following:
var studentIDs = new HashSet<string>(students.Select(x => x.StudentID));
This will speed up your execution times. Please let me know if it works.
I think your approach to the logic is fine. I think you can present it in a clearer and easier way. Consider the below:
HashSet<string> studentIDs = students.Select(s => s.StudentID)
.ToHashSet();
string StudentID(RawDataStudent s) => string.IsNullOrWhiteSpace(s.StudentNumber)
? $"{s.EnrollNumber}{s.SequenceNumber}"
: $"{s.StudentNumber}{s.SequenceNumber}";
var rawData = StudentManager.GetAllData();
var resultList = rawData.Where(s => !studentIDs.Contains(StudentID(s)))
.ToList();
Important points:
Pulling the entire 'contains' lambda out and presenting it as a clearly named function with intent - good readability
Always try and work in the affirmative with booleans - specifically you ended up with this weird bracketed negation with the null or whitespace, just switch the returns around - again also easier to read
As other posters have commented, calling contains against a HashSet will be considerably faster
Note I've assumed your GetAllData return type somewhat - good example of when var is a bit evil

Compare Json Collection, return change values

I have Json Collection with the different fields. All fields are dynamic. Please take the below example.
[{"KB":"1","Id":"01","MemCode":1,"A":"2","B":"1","C":"2010-01-01T00:00:00","D":1}
{"KB":"1","Id":"01","MemCode":2,"A":"2","B":"1","C":"2010-01-01T00:00:00","D":2},
{"KB":"1","Id":"01","MemCode":2,"A":"2","B":"1","C":"2010-01-01T00:00:00","D":3},
{"KB":"1","Id":"01","MemCode":2,"A":"2","B":"1","C":"2010-01-01T00:00:00","D":4}]
I want to compare Four number json with the first one and identify the changes,
Like in fourth line Memcode is 2 and in first Memcode is 1. So here memcode is change from 2 to 1.
Like wise for all the fields. this field may be any type like datetime/ string etc. This is just example. JSON may be long with many fields. But all json string is same fields.
All fields are dynamic. I want some method which do above calculation and return field change with the old and new values.
I want to do using C# and Newtonsoft.Json. I don't know how to achieve above one. Can you please help me/guide me?
Thank you in advance.
EDIT :- 5/10
Hello, Sorry If I am not clear. Let me Explain Once again. I want develop some generic method who accept the collection of the JSON. This JSON have a number of different fields.
Suppose Collection have a 5 JSON. ALl 5 JSON have a same number of fields with a different value or may be same values.
Now I want to compare 1st number of JSON with the N number of JSON. Identify which field has been changes. Take that field and it's old value/New value in the Collection. Old value will be N field value and New value will be 1 field value. Continue this way for other JSON. Now 1st Number JSON compare with the N-1. and identify change fields. Continue this way up to all collection finished.
Return value be Fields and Old value, New value.
The field can by string, number of date.
I can do using for loop but I want some generic method which is time efficient and align with the new C# feature.
Hope I am clear this time.
Thank you so much..
Use dynamic and convert your Json object as bellow
dynamic data= JsonConvert.DeserializeObject(your Json Object);
Then use normal foreach loop on data to compare
You could convert each JSON object to List<string> where string represents one or more JSON attributes. Then compare those lists using Except method. Each JSON object is serialized to string which is then split by ,. By splitting, JSON attributes are extracted. objArray is the array containing JSON objects.
List<List<string>> jsonAttList = new List<List<string>>();
int objArrayLength = objArray.Length;
for (int i = 0; i < objArrayLength; i++)
{
string objString = JsonConvert.SerializeObject(objArray[i]);
jsonAttList.Add(objString.Split(',').ToList());
}
Or shorter
List<List<string>> jsonAttList = new List<List<string>>();
objArray.ForEach(item => jsonAttList.Add(JsonConvert.SerializeObject(item).Split(',').ToList()));
Here are four examples you provided with one additional attribute.
[{"KB":"1","Id":"01","MemCode":1,"A":"2","B":"1","myObj":{"X":1,"Y":2},"C":"2010-01-01T00:00:00","D":1},
{"KB":"1","Id":"01","MemCode":2,"A":"2","B":"1","C":"2010-01-01T00:00:00","D":2}
{"KB":"1","Id":"01","MemCode":2,"A":"2","B":"1","myObj":{"X":1,"Y":3},"C":"2010-01-01T00:00:00","D":3},
{"KB":"1","Id":"01","MemCode":2,"A":"2","B":"1","myObj":{"X":1,"Y":2,"Z":3},"C":"2010-01-01T00:00:00","D":4}]
Difference between two JSON objects is list of strings.
Difference between first and second JSON object is list containing: "MemCode":1, "myObj":{"X":1, "Y":2} and "D":1}.
var difference01 = jsonAttList[0].Except(jsonAttList[1]).ToList();
Difference between first and third JSON object is list containing: "MemCode":1, "Y":2} and "D":1}.
var difference02 = jsonAttList[0].Except(jsonAttList[2]).ToList();
Difference between first and fourth JSON object is list containing: "MemCode":1, "Y":2} and "D":1}.
var difference03 = jsonAttList[0].Except(jsonAttList[3]).ToList();
Difference between fourth and first JSON object is list containing: "MemCode":2, "Y":2, "Z":3} and "D":4}.
var difference30 = jsonAttList[3].Except(jsonAttList[0]).ToList();

Getting a list item by index

I've recently started using c# moving over from Java. I can't seem to find how to get a list item by index. In java to get the first item of the list it would be:
list1.get(0);
What is the equivalent in c#?
list1[0];
Assuming list's type has an indexer defined.
You can use the ElementAt extension method on the list.
For example:
// Get the first item from the list
using System.Linq;
var myList = new List<string>{ "Yes", "No", "Maybe"};
var firstItem = myList.ElementAt(0);
// Do something with firstItem
Visual Basic, C#, and C++ all have syntax for accessing the Item property without using its name. Instead, the variable containing the List is used as if it were an array:
List[index]
See, for instance, List.Item[Int32] Property.
.NET List data structure is an Array in a "mutable shell".
So you can use indexes for accessing to it's elements like:
var firstElement = myList[0];
var secondElement = myList[1];
Starting with C# 8.0 you can use Index and Range classes for accessing elements. They provides accessing from the end of sequence or just access a specific part of sequence:
var lastElement = myList[^1]; // Using Index
var fiveElements = myList[2..7]; // Using Range, note that 7 is exclusive
You can combine indexes and ranges together:
var elementsFromThirdToEnd = myList[2..^0]; // Index and Range together
Also you can use LINQ ElementAt method but for 99% of cases this is really not necessary and just slow performance solution.
Old question, but I see that this thread was fairly recently active, so I'll go ahead and throw in my two cents:
Pretty much exactly what Mitch said. Assuming proper indexing, you can just go ahead and use square bracket notation as if you were accessing an array. In addition to using the numeric index, though, if your members have specific names, you can often do kind of a simultaneous search/access by typing something like:
var temp = list1["DesiredMember"];
The more you know, right?
you can use index to access list elements
List<string> list1 = new List<string>();
list1[0] //for getting the first element of the list

c# search arraylist problem

In my code I have an arraylist, called heart, which contains numbers from 1-13.
heart.Add("any");
for(int i = 0; i < 14; i++)
{
heart.Add(i);
}
As you can see it also contains "any" placed in the first element. When I use this code to get the all of the elements that has a value over 5 I get an error.
int store = heart.Cast<int>().Where(item => item > 5).Count().ToString();
I get the error "Specified cast is not valid" and that's because of the
"any" I have in the first element. Could anyone help me fix this?
It sounds like you just need the OfType method instead:
string store = heart.OfType<int>().Where(item => item > 5).Count().ToString();
OfType only returns values which are of the approriate type, ignoring others. See my Edulinq blog post on it for more information.
As Sven shows, you can also use the overload of Count which takes a predicate, to remove the Where call:
string store = heart.OfType<int>().Count(item => item > 5).ToString();
(I've changed the variable type given that you're calling ToString at the end... again, you may want to think about this decision. It depends on how you're using it of course.)
However, I'd strongly advise you to use a strongly-typed collection instead of ArrayList. Think about what the collection is meant to hold - it seems odd to hold both strings and integers. What are you trying to do with it?
Use this instead:
int count = heart.OfType<int>().Count(item => item > 5);
OfType will filter the list and return only those elements that are the correct type, rather than Cast which tries to cast all elements.
You can't cast the word "any" to an integer, that's pretty straight forward.
We'd have to know exactly what your trying to do with here, and how the array is used to really give a good recommendation.
Since you're using int and you wanted values of 1-13, may I suggest you use an int value of 0 to represent 'any'?
You could do
Int store = heart.GetRange(1, heart.Count - 1).Cast<int>().Where(item => item > 5).Count().ToString();

NULLs in string array

How to remove Null values in string array
Like { ,-2,3, ,-4,+5, ,66...}
I need to remove those null values in between and re-size the array
I don't want to use lists
I don't want to create a new array
Please let me know if it is possible with simple code.
Thank You.
No, it's not possible without creating a new array. You can't resize an array.
You can easily create a new array without empty strings and null references like this:
string[] items = new string[] { "", "-2", "3", null, "-4", "+5", null, "66" };
items = items.Where(s => !String.IsNullOrEmpty(s)).ToArray();
If you don't want to create a new array, then no, it's not possible. You cannot add or remove an item from a simple array (as in, string[]).
The most straightforward way to accomplish what you want to achieve (if you remove your second requirement) would be:
Count the number of null values in your source array
Create a new array of the same length as your source array minus the number of nulls from step 1
Copy all non-null values from your source array into the new array
(Optional) Set the reference to your source array (e.g., srcArray) to your new array
As Dan said, you can't add or remove values from an Array. You can, however, use LINQ to remove the values and produce a second array.
originalArray = originalArray.Where(s => !string.IsNullOrEmpty(s)).ToArray()
Probably not the most performant solution but...
array.Where(s => s != null).ToArray();
It will create a new array, but I cannot think of a solution that won't.
Before deciding how to proceed, you really need to think about who holds a reference to the array you are operating on.
If the array is not referenced by any other code (as a member of a class, as a captured variable in a lambda, or in some collection somewhere) then you shouldn't worry about creating a new array. In that case I would use something like what #Codesleuth or #Guffa suggest.
However, if other code may exist that holds a reference to this same array - then you are out of luck, unless you can safely identify and update the references held in those other places. This is a hard thing to do - and you should be very careful assuming that you can always update all other places where a reference is held.
Am I the only one here that would scan the array and move the members back over the NULLs, therefore making a continuous list of non-nulls.
This doesn't create a new array and it's simple to implement and it's immportant to know you can move the entries around the array.
Unfortunately I'm at work so can not supply full code, however you would implement it by searching the array for NULLs then moving the remaining items in the array up one. Keep doing this until the end. I would suggest clearing the remaining entires once the search is completed.
string[] _array= new string[] { "", "z", "d", null, "a", "b", null, "66" };
// select non-null elements only
_array= _array.Where(a => !String.IsNullOrEmpty(a)).ToArray();

Categories

Resources