separating strings by some text within listbox - c#

I have a ListBox where table names are written like this:
Staging_Section_01_2019_03_19_01
Staging_Section_01_2019_03_20_01
Staging_Section_23_2019_03_21_01
Staging_Section_52_2019_03_23_01
Staging_Section_52_2019_03_24_01
What I am trying to do is to separate them by Section Number, so I want all Section_01 in one List object and Section_23 in another List object, so on and so forth. The dynamic nature is whats making it difficult for me.
So far, I have the following:
foreach (var it in uploadBox.Items)
{
if (it.ToString().Contains("Section"))
{
section = it.ToString().Substring(0, 18);
found = it.ToString().IndexOf("_");
section = section.Substring(found + 1);
sectionNum = section.Substring(8, 2);
}
}
I have gotten the sectionNum which would just be the number and section, which is the string like Section_01.
Any idea on how to approach this?
The expected output would be something like this:
List 1
Staging_Section_01_2019_03_19_01
Staging_Section_01_2019_03_20_01
List 2
Staging_Section_23_2019_03_21_01
List 3
Staging_Section_52_2019_03_23_01
Staging_Section_52_2019_03_24_01

I would use a Dictionary<string, List<string>> for this. Each 'section' that is parsed would be a key, and the remaining portion would the the value.
Dictionary<string, List<string>> myDict = new Dictionary<string, List<string>>();
foreach (var it in uploadBox.Items)
{
if (it.ToString().Contains("Section"))
{
section = it.ToString().Substring(0, 18);
found = it.ToString().IndexOf("_");
section = section.Substring(found + 1);
sectionNum = section.Substring(8, 2);
if(!myDict.ContainsKey(sectionNum))
{
myDict.Add(sectionNum, new List<string> { someOtherValue });
}
else
{
myDict[sectionNum].Add(someOtherValue);
}
}
}
Unless I have completely misinterpreted your question, I think this is a potential solution to your dynamic objects.

you could do something like this:
var sections = new Dictionary<string, List<string>>();
foreach(var it in uploadBox.Items)
{
var item = it.ToString();
if(item.Contains("Section"))
{
var section = GetSection(item);
if(!sections.ContainsKey(section))
{
sections.Add(section, new List<string>());
}
sections[section].Add(item);
}
}
private string GetSection(string item)
{
var split = item.Split("_");
return $"{split[1]}_{split[2]}";
}

It is best to regex for this kind of task:
uploadBox.Items
.GroupBy(x => Regex.Match(x.ToString(), #"^\w+_Section_(?<section>\d+)").Groups["section"].Value)

Related

C# string to var object

I have a string "hello", and a integer 1.
I want to convert them into
new { hello= 1 }
dynamically, and without using any condition like
switch(p1){
case "hello":
return new {hello=p2};
}
as there is many different string and I need to put many items into a super object set like
var emotion = {smile=1,angry=2,worry=3}
the problem is smile, angry and worry was string. but after added to emotion, they are not string, but just an index (like dictionary, however dictionary's index also has dataType, which is not my expected result)
Is it possible?
--- Updated --- i have added a function to specify the expected output.
private void Question_1()
{
//i have
string a = "hello";
int b = 1;
// i want to convert a and b to new {a = b} programmatically, for example i can convert a and b to a Tuple like
Tuple<string, int> x = new Tuple<string, int>(a,b);
//but i dont know how to to convert it to new {a = b}, as i need to put the string "hello" as key to new {a=b}
var result = new { hello = b }; //you can see i can put b after =, but i can never put the string hello at the left
}
private void Question_2()
{
//and the final should be like this
List<Tuple<string, int>> list = new List<Tuple<string, int>>() {
new Tuple<string,int>("smile",1),
new Tuple<string,int>("cry",2),
new Tuple<string,int>("worry",3)
};
foreach (Tuple<string, int> item in list)
{
//adding item's string and int into result and finally the result is
}
//the final result
var finalResult = new { smile = 1, cry = 2, worry = 3 };
}
Use .NET naming conventions for enums: They should be Pascal Notation.
enum Emotion
{
Smile = 1, Angry = 2, Worry = 3
}
var l = new List<Emotion> { Emotion.Angry, Emotion.Smile, Emotion.Worry };
You can also use a friendly name for your enum with the DesriptionAttribute like this:
enum Emotion
{
[Description("Smiling")]
Smile = 1,
[Description("Angry Type")]
Angry = 2,
[Description("Worry Type")]
Worry = 3
}
Any reason you can't just use a dictionary?
var hi = new Dictionary<string,int>();
hi[p1] = p2;
return hi; // Would serialize the same way as your anonymous object
If not, then you could use the expando object to dynamically set properties at runtime.
var hi = new ExpandoObject() as IDictionary<string, object>;
hi.Add(p1, p2);
var p2Value = (int)((dynamic)hi).hello;
You can use ExpandoObject.
class Program
{
static dynamic obj = new ExpandoObject();
static void Main(string[] args)
{
AddProperty("City", "Sydney");
AddProperty("Country", "Australia");
AddProperty("hello", 1);
Console.WriteLine(obj.City);
Console.WriteLine(obj.Country);
Console.WriteLine(obj.hello);
//We can even use dynamic property names ( e.g. cityProp in below example )
IDictionary<string, object> dic = obj as IDictionary<string, object>;
Console.WriteLine("City is : " + dic[cityProp]);
}
public static void AddProperty(string propertyName, object value)
{
IDictionary<string, object> a = obj as IDictionary<string, object>;
a[propertyName] = value;
}
}
dynamic emotion = new { smile = 1, angry = 2, worry = 3 };
Console.WriteLine(emotion.smile);
Like this?
Edit: Based on your comment on another answer:
it is not worked, i need it able to be accepted by
Url.Action("action","controller", x), where x is thing that i'm trying
to create dynamically . i don't know if dynamic too complex or what.
but Url.Action dont know how to read it
There's obviously more to the question than just C#, clearly this an MVC question. You should really add as much information as you can about what you need.
Your answer is probably here:
https://stackoverflow.com/a/15112223/1685167
The #Url.Action() method is proccess on the server side, so you cannot
pass a client side value to this function as a parameter.

Searching a nested List<T>

I have this data structure:
class Conference
{
private List<List<string>>_orgs;
public List<List<string>> Orgs
{
set { _orgs = value; } get { return _orgs; }
}
}
Data in this collection:
List<string> sublist = new List<string>();
sublist.Add("university");
sublist.Add("organization");
List<List<string>> list = new List<List<string>>();
list.Add(sublist);
Then:
Conference c = new Conference();
c.Orgs = list;
I have collection of conference objects:
List<Conference> listConferences = new List<Conference>();
listConferences.Add(c);
I want search a string like "uni" and find collection of conference have orgs like "uni". How can I do this?
You can do this:
var selection = listConferences
.Where(x => x.Orgs.SelectMany(y => y).Any(y => y.Contains("uni")))
.ToList();
Note:
the trailing ToList() might not be necessary depending on your needs (e.g. if you iterate selection only once you can skip it).
Please use this code, below;
instead of third one, you may use your own conference list. you can now use similar to like keyword.
List<string> first = new List<string>();
first.Add("University");
first.Add("Standard");
List<List<string>> second = new List<List<string>>();
second.Add(first);
List<List<List<string>>> third = new List<List<List<string>>>();
third.Add(second);
var e = third.Find(delegate(List<List<string>> r)
{
bool isValid = false;
if(r.Count > 0)
{
foreach(List<string> s in r)
{
if(s.Count > 0 )
{
isValid = s.FindAll(delegate(string t){ return t.StartsWith("uni", StringComparison.OrdinalIgnoreCase);}).Count > 0;
}
}
}
return isValid;
});
Done, one more workout using linq. You should be feeling comfortable with this:
var univ = from p in c.Orgs
select p.FindAll(r => r.FindAll(s => s.StartsWith("univ", StringComparison.OrdinalIgnoreCase)));

Creating objects dynamically in loop

I have an array of strings that I am looping through. I would like to loop through the array and on each iteration, create a new object with a name that matches the string value.
For example;
string[] array = new string[] { "one", "two", "three" };
class myClass(){
public myClass(){
}
}
foreach (string name in array)
{
myClass *value of name here* = new myClass();
}
Would result in three objects being instantiated, with the names "one", "two" and "three".
Is this possible or is there are better solution?
What are you trying to do is not possible in statically-typed language. IIRC, that's possible on PHP, and it's not advisable though.
Use dictionary instead: http://ideone.com/vChWD
using System;
using System.Collections.Generic;
class myClass{
public string Name { get; set; }
public myClass(){
}
}
class MainClass
{
public static void Main()
{
string[] array = new string[] { "one", "two", "three" };
IDictionary<string,myClass> col= new Dictionary<string,myClass>();
foreach (string name in array)
{
col[name] = new myClass { Name = "hahah " + name + "!"};
}
foreach(var x in col.Values)
{
Console.WriteLine(x.Name);
}
Console.WriteLine("Test");
Console.WriteLine(col["two"].Name);
}
}
Output:
hahah one!
hahah two!
hahah three!
Test
hahah two!
While others have given you an alternate but no one is telling why do they recommend you that.
That's because You cannot access object with dynamic names.
(Food for thought: Just think for a moment if you could do so, how will you access them before they are even coded/named.)
Instead create a Dictionary<string, myClass> as others mentioned.
Use a Dictionary<String, myClass> instead:
var dict= new Dictionary<String, myClass>();
foreach (string name in array)
{
dict.Add(name, new myClass());
}
Now you can access the myClass instances by your names:
var one = dict["one"];
or in a loop:
foreach (string name in array)
{
myClass m = dict[ name ];
}
You can use this approach:
var array = [srt1, srt2, str3];
var other_array = [];
for(var i = 0; i < array.length; i++){
other_array.push({
name: array[i]
})
}
And for lookup it is easy to find the instance you need by filtering:
var instance1 = other_array.filter(function(result) {
return result.name == 'str1';
});
Looks like you need a list of dictionary of your objects:
var myClassDictionary = new Dictionary<string,myClass>();
foreach (string name in array)
{
myClassDicationry.Add(name, new myClass());
}
// usage:
// myClass["one"] <- an instance of myClass
There are no programming languages that I know of that let you define variable names in runtime.
You could do something like this -
Dictionary<string, myClass> classes = new Dictionary<string, myClass>();
foreach(string name in array)
{
classes[name] = new myClass();
}
Then you can refer to the named instances later
classes[name].MyClassMethod();
You can use the following code.
string[] array = new string[] { "one", "two", "three" };
Dictionary<String, myClass> list;
class myClass(){
public myClass(){
list = new Dictionary<String, myClass>();
}
}
foreach (string name in array)
{
list.Add(name, new myClass())
}
You can use lists to store the objects so you can access them
list<myClass> myClasses = new List<myClass>();
foreach (myClass object in myClasses)
{
//preform interaction with your classes here
}
Not applicable to C#, or any statically-typed language for that matter.
For curiosity, I tried if what I remembered in PHP(creating variables on-the-fly) is still correct.
It's still the same PHP, last I used it was year 2000. You can generate variables on-the-fly, not saying it's advisable though, it pollutes the global variables, it can corrupt some existing variable or object with same name.
https://ideone.com/nJDiou
<?php
class MyClass
{
private $v;
function __construct($x) {
$this->v = $x;
}
public function getValue() {
return $this->v;
}
}
$one = new MyClass("I'm tough!");
echo "The one: " . $one->getValue() . "\n";
$i = 0;
foreach(array("one","two","three") as $h) {
$$h = new MyClass("Says who? " . ++$i);
}
echo "The one: " . $one->getValue() . "\n";
echo $two->getValue() . "\n";
echo $three->getValue() . "\n";
echo "loop\n";
foreach(array("three","one","two") as $h) {
echo $$h->getValue() . "\n";
}
?>
Outputs:
The one: I'm tough!
The one: Says who? 1
Says who? 2
Says who? 3
loop
Says who? 3
Says who? 1
Says who? 2

Dictionary<string, int> increase value

I have a Dictionary<string, int> and I am reading some strings from a list... I want to add them in the dictionary, but if the string is already in the dictionary, I want its value to increase by 1.
The code I tried is as below, but there are some strings that are increased with every input.. Is something wrong?
Dictionary<string, int> dictionary = new Dictionary<string, int>();
foreach (String recordline in tags)
{
String recordstag = recordline.Split('\t')[1];
String tagToDic = recordstag.Substring(0, (recordstag.Length-1) );
if (dictionary.ContainsKey(tagToDic) == false)
{
dictionary.Add(tagToDic, 1);
}
else
{
try
{
dictionary[tagToDic] = dictionary[tagToDic] + 1;
}
catch (KeyNotFoundException ex)
{
System.Console.WriteLine("X" + tagToDic + "X");
dictionary.Add(tagToDic, 1);
}
}
}
EDIT: To answer your comments... I am removing the last char of the string because it is always a blank space...
My input is like:
10000301 business 0 0,000
10000301 management & auxiliary services 0 0,000
10000316 demographie 0 0,000
10000316 histoire de france 0 0,000
10000347 economics 0 0,000
10000347 philosophy 1 0,500
and i want only the string like "business" or "management & auxiliary services" etc.
You are splitting each string in the input string array and selecting the 2nd string in the string array. Then you are removing the last character of this 2nd string using SubString. Hence all strings that differ only in the last character would be considered the same and incremented. Thats why you might be seeing "some strings that are increased with every input".
EDIT: If the purpose of removing the last char is to remove space, Use String.Trim instead.
Another edit is using TryGetValue instead of ContainsKey which performs better to increment your value. Code has been edited below.
Try this:
Dictionary<string, int> dictionary = new Dictionary<string, int>();
foreach(string recordline in tags)
{
string recordstag = recordline.Split('\t')[1].Trim();
int value;
if (!dictionary.TryGetValue(recordstag, out value))
dictionary.Add(recordstag, 1);
else
dictionary[recordstag] = value + 1;
}
No need for a dictionary, can be solved using this Linq query.
(Assuming you want the complete string after \t)
var q =
from s in tags.Select (t => t.Substring(t.IndexOf("\t")))
group s by s into g
select new
{
g.Key,
Count = g.Count()
};
And if you need it as a dictionary just add:
var dic = q.ToDictionary (x => x.Key, x => x.Count);
Your input string first split and then substring of it returned to tagToDic, So maybe n strings have a same tagToDic.
Extension method
public static void Increment(this Dictionary<string, int> dictionary, string key)
{
int val;
dictionary.TryGetValue(key, out val);
if (val != null)
dictionary[key] = val + 1;
}
Dictionary<string, int> dictionary = new Dictionary<string, int>();
// fill with some data
dictionary.Increment("someKey");
It's probably easier just to re-add the dictionary value after you retrieve the count from the existing one.
Here's some psuedo code to handle the look up logic.
Dictionary<string, int> _dictionary = new Dictionary<string, int>();
private void AdjustWordCount(string word)
{
int count;
bool success = _dictionary.TryGetValue(word, out count);
if (success)
{
//Remove it
_dictionary.Remove(word);
//Add it back in plus 1
_dictionary.Add(word, count + 1);
}
else //could not get, add it with a count of 1
{
_dictionary.Add(word, 1);
}
}
How about:
Dictionary<string, int> dictionary = new Dictionary<string, int>();
string delimitedTags = "some tab delimited string";
List<string> tags = delimitedTags.Split(new char[] {'\t'}, StringSplitOptions.None).ToList();
foreach (string tag in tags.Distinct())
{
dictionary.Add(tag, tags.Where(t => t == tag).Count());
}
If you have them in a list you could just group them and make your list.
list.GroupBy(recordline => recordline.Split('\t').Substring(0, (recordstag.Length-1),
(key, ienum) => new {word = key, count = ienum.Count()});
Then you can put that in a dictionary or iterate it or something.
Your dictionary code looks like it will function the way you expect.
My best guess is that your string-splitting code is not working correctly.
You'd have to give us some sample inputs to verify this though.
Anyway, your entire block of code could be simplified and rewritten with LINQ as:
var dictionary = tags
.Select(t => {
var recordstag = t.Split('\t')[1];
return recordstag.Substring(0, recordstag.Length-1);
})
.GroupBy(t => t)
.ToDictionary(k => k.Key, v => v.Count())
;

C#: Adding data to dictionary

I have a list like
List<string> TempList = new List<string> { "[66,X,X]", "[67,X,2]", "[x,x,x]" };
I need to add data to the dictionary from the above list
Dictionary<int, int> Dict = new Dictionary<int, int>();
so the Dict should contain
Key --> 66 value --> 67
i need to take 66(first value) from first string([66,X,X]) and 67(first value) from second string( [67,X,X]) and add it as a key value pair into the dictionary.
Now i'm following string replacing and looping methodology to do this .
Is there any way to do this in LINQ or Regular expression.
After your comment that you're starting from a list of lists, I understood what you were after. I'm reusing Jaroslav's 'GetNumber' function here. Wrote my sample with array of array of string, but should work just the same. The code below will throw if you have duplicate keys, which I presume is what you want if you're using a dictionary.
var input = new []
{
new [] { "[66,X,X]", "[67,X,2]", "[x,x,x]" },
new [] { "[5,X,X]", "[8,X,2]", "[x,x,x]" }
};
var query = from l in input
select new
{
Key = GetNumber(l.ElementAt(0)),
Value = GetNumber(l.ElementAt(1))
};
var dictionary = query.ToDictionary(x => x.Key, x => x.Value);
Here is an example using both string.Split() and a Regex:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<string> data = new List<string>() { "[66,X,X]", "[67,X,2]", "[x,x,x]" };
addToDict(data);
Console.ReadKey();
}
private static void addToDict(List<string> items)
{
string key = items[0].Split('[', ',')[1];
string val = items[1].Split('[', ',')[1];
string pattern = #"(?:^\[)(\d+)";
Match m = Regex.Match(items[0], pattern);
key = m.Groups[1].Value;
m = Regex.Match(items[1], pattern);
val = m.Groups[1].Value;
_dict.Add(key, val);
}
static Dictionary<string, string> _dict = new Dictionary<string, string>();
}
}
i suspect that your example is quite contrived though, so there may be a better solution especially if you need to process large numbers of strings into key/value pairs (i deliberately hardcoded index values because your example was quite simple and i didn't want to over complicate the answer). If the input data is consistent in format then you can make assumptions like using fixed indexes, but if there is a possibility of some variance then there may need to be more code to check the validity of it.
You can use a regular expression to extract the value from each item in the list, and if you want, use LINQ to select out two lists and zip them together (in C# 4.0):
var regex = new Regex(#"\d+");
var allValues = TempList.Select(x =>int.Parse(regex.Match(x).Value));
var dictKeys = allValues.Where((x,index)=> index % 2 == 0); //even-numbered
var dictValues = allValues.Where((x,index)=> index % 2 > 0); //odd numbered
var dict = dictKeys.Zip(dictValues, (key,value) => new{key,value})
.ToDictionary(x=>x.key,x=>x.value);
If you're using C# 3.5, you can use Eric Lippert's implementation of Zip().
IF I understand correctly: you want to create linked nodes like 66 -> 67, 67 -> 68, ... n -> n+1?
I would not use LINQ:
private static int GetNumber(string s)
{
int endPos = s.IndexOf(',');
return Int32.Parse(s.Substring(1, endPos-1));
}
And in code:
int first, second;
for (int i = 1; i < TempList.Count; i++)
{
first = GetNumber(TempList[i - 1]);
second = GetNumber(TempList[i]);
Dict.Add(first, second);
}
You should also perform checking, etc.
The sample assumes a list with at least 2 items.
List<List<string>> source = GetSource();
Dictionary<int, int> result = source.ToDictionary(
tempList => GetNumber(tempList[0]),
tempList => GetNumber(tempList[1])
);

Categories

Resources