I am trying to convert a string to key value pair for testing purposes. The issue I have is that when I split the string, the value can be null in rare occasions
For example:
"Sent On\r\n2021-01-31 09:18:42"
"Priority\r\nLow"
When I use the following code it works fine for all records except when value is null. There will always be a key
Dictionary<string, string> details = new Dictionary<string, string>();
foreach (var row in Rows)
{
var text = row.Text.Replace("\r\n", ",");
var splitText = text.IndexOf(",");
var key = text.Substring(0, splitText);
var value = text.Substring(splitText + 1);
details.Add(key, value);
}
return details;
The issue is when the text is like this and I only have a key and no value. I cant split the text either by '\r\n' as it doesnt have a value
"Read On"
how can I modify my code to check if this scenario?
Give this a go:
foreach (var row in Rows)
{
var parts = row.Text.Split(new [] { Environment.NewLine }, StringSplitOptions.None);
var key = parts[0];
var value = parts.Length > 1 ? parts[1] : null;
details.Add(key, value);
}
Or even this:
Dictionary<string, string> details =
Rows
.Select(row => row.Text.Split(new [] { Environment.NewLine }, StringSplitOptions.None))
.ToDictionary(parts => parts[0], parts => parts.Length > 1 ? parts[1] : null);
Related
could you help splitting a string into key value pairs around the colon delimiter. I am having trouble with this.
eg.
"somekey:value1 value2 another:<value3 one_more:value4..value5"
output
<"somekey", "value1 value2">
<"another", "<value3">
<"one_more", "value4..value5">
This if you just want a simple conversion. you can also use regex.
private static Dictionary<string, string> Dictionary(string str)
{
var dictionary = new Dictionary<string, string>();
var splitOnSpace = str.Split(" ");
var value = string.Empty;
var key = "";
var i = 0;
while (i < splitOnSpace.Length)
{
var item = splitOnSpace[i];
if (item.Contains(":"))
{
var split = item.Split(':');
key = split[0];
value = split[1];
dictionary.Add(key, value);
}
else
{
value += " " + item;
dictionary[key] = value;
}
i++;
}
return dictionary;
}
The regex extracting such key-value pairs is
([^\s:]+):(.*?)(?=\s+[^\s:]+:|$)
(Demo)
The tricky part here is (?=\s+[^\s:]+:|$) lookahead, which tells the "match anything for value" regex ((.*?)) stop as soon as it encounters the next key preceded by some spaces (\s+[^\s:]+:) or simply end of string ($).
Then the match groups can be extracted as follows:
var input = "somekey:value1 value2 another:<value3 one_more:value4..value5";
var matches = Regex.Matches(input, #"([^\s:]+):(.*?)(?=\s+[^\s:]+:|$)");
var pairs = matches.Select(m => (m.Groups[1].Value, m.Groups[2].Value));
foreach (var (key, value) in pairs)
{
Console.WriteLine($"<\"{key}\": \"{value}\">");
}
Full demo
You can try this regex.
string givenString =
#"key1:value1 value2 key2:<value3 key3:value4..value5";
Dictionary<string, string> result1 = Regex
.Split(givenString, "([a-z0-9]+:)")
.Skip(1) // will skip the first empty
.Select((item, index) => new {
value = item.Trim(),
index = index / 2
})
.GroupBy(item => item.index)
.ToDictionary(chunk => chunk.First().value.TrimEnd(':'),
chunk => chunk.Last().value);
I have list of value
list1[110,120,130]
I want to check in dictionary whether my dictionary table column value like
110_abc_ro
120_cfg_go
130_dfg_lo
110_abc_io
170_cfg_jo
is contained list value or not.
I want output like
110_abc_ro,110_abc_io is for list value 110
As I can't tell what your dictionary name/key-type is from the question, I came only as far as this. For every list-item (110, 120, etc.) you now iterate through the entries in your dictionary. Whenever a value from your dictionary contains the value you're iterating over from the list, it'll write it to a string, which you can then send/write/something else.
foreach (int i in list1)
{
string output = "";
foreach (KeyValuePair<var, string> kvp in yourDictionary)
{
if (kvp.Value.Contains(i.ToString()))
{
output += kvp.Value + ", ";
}
}
//print your outputstring here.
}
Edit:
you can use yourDictionary.Values.Select(x => x.Value.Contains(i.ToString())); instead of the foreach. Using a little from Lucifer's answer, you can turn it into the following;
foreach (int i in list1)
{
string output = String.Join(",", yourDictionary.Values.Select(x => x.Value.Contains(i.ToString())));
}
You can use String.Join() to join all values which match your list of int
As per MSDN this method Concatenates all the elements of a string collection, using the specified separator between each element.
eg:
string values = String.Join(",", yourDictionary.Where(x => list.Any(ele => x.Value.Contains(ele.ToString()))).Select(x => x.Value).ToList());
Try this:
string result= "";
list1.ForEach(item => {
yourDictionary.ToList().ForEach
(
pair =>
{
if (pair.Value.Contains(item.ToString()))
{
result = result + pair.Value + ", ";
}
}
);
});
Here you have simple solution:
int[] list1 = { 110, 120, 130 };
List<string> dict = new List<string> { "110_abc_ro", "120_cfg_go", "130_dfg_lo", "110_abc_io", "170_cfg_jo" };
for (int i = 0; i < list1.Length; i++)
{
string str = "Values from dictionary containing " + list1[i] + ":\n";
str += String.Concat(dict.Where(val => val.Contains(list1[i].ToString())).Select(val => val + ", "));
Console.Write(str);
}
I have this code snippet as below which iterates over a split string.
if (!string.IsNullOrEmpty(profile.ContactNumber))
{
var splitContract = profile.ContactNumber.Split(new string[] { "and", "&" }, StringSplitOptions.RemoveEmptyEntries);
foreach (var contract in splitContract)
{
//check the split if it contains "x" or "X" character - if it does contain, it means it's a valid contract
if (contract.Contains("x") || contract.Contains("X"))
{
var condensedString = contract.Replace(" ", "");
var split = condensedString.Split(new char[] { 'x', 'X' });
GetNumbersOnly(split);
}
}
}
private void GetNumbersOnly(string[] inputArray)
{
var ListKeyValuePair = new List<KeyValuePair<string, string>>();
foreach (var item in inputArray)
{
var numberToAdd = Regex.Replace(item, "[^0-9]", "", RegexOptions.None);
ListKeyValuePair.Add(?, ?);
}
}
In GetNumbersOnly method, how can I populate List of KeyValuePair inside the for each loop?
The inputArray variable has an array element of [0] = 100, [1] = 5 for the first iteration and so on.
This is the desired output for the KeyValuePair {100, 5}, {200, 10}, {500, 15}.
Sorry, I can't seem to find any related scenario when I googled it. Any help with this is greatly appreciated.
Because the key and value are stored in separate array items, your logic is dependent on order. In cases like this, you should avoid for...each and instead use plain old for, which allows you to control the manner of iteration.
private void GetNumbersOnly(string[] inputArray)
{
var ListKeyValuePair = new List<KeyValuePair<string, string>>();
for (int i=0; i< inputArray.Length; i+=2) //The "2" here is very important!
{
var numberToAdd1 = Regex.Replace(inputArray[i], "[^0-9]", "", RegexOptions.None);
var numberToAdd2 = Regex.Replace(inputArray[i+1], "[^0-9]", "", RegexOptions.None);
ListKeyValuePair.Add(new KeyValuePair<string, string>(numberToAdd1, numberToAdd2));
}
}
The ListKeyValuePair.Add( ) function is expecting 1 field which is of type KeyValuePair. You need to make one of these with a new KeyValuePair() { key = item, value = numberToAdd };
Why are you keeping key value pairs in a list? Why not a Dictionary ? Do you want duplicate pairs?
This is the code using LINQ, it stores the values into list
string StringRegex = "\"(?:[^\"\\\\]|\\\\.)*\"";
Dictionary<string, string> dictionaryofString = new Dictionary<string, string>()
{
{"String", StringRegex}
};
var matches = dictionaryofString.SelectMany(a => Regex.Matches(input,a.Value)
.Cast<Match>()
.Select(b =>
new
{
Index = b.Index,
Value = b.Value,
Token = a.Key
}))
.OrderBy(a => a.Index).ToList();
for (int i = 0; i < matches.Count; i++)
{
if (i + 1 < matches.Count)
{
int firstEndPos = (matches[i].Index + matches[i].Value.Length);
if (firstEndPos > matches[(i + 1)].Index)
{
matches.RemoveAt(i + 1);
i--;
}
}
}
foreach (var match in matches)
{
Console.WriteLine(match);
}
Can it not be stored into Array? Where I can display only item I want. Just like here the output is {Index=, Value=, Token=}
Meanwhile I want the output that be of just "Value" "Token" index not needed.
You can use ToArray instead. But List gives you the desired array functionality already, you can access an item by its index.
var exampleQuery = select c from componentsDemo;
var list = exampleQuery.ToList();
var secondElement = list[1]; // <- demo only, there could be an exception thrown, if there's less than two elements in the list
EDIT: as I can see from your comments, you need this:
foreach (var match in matches)
{
Console.WriteLine(match.Value + ", " + match.Token);
}
string format
addr,hname,beam,txrate,rxrate,dcap,ucap,txuse,rxuse,rxrssi0,rxrssi1,txrssi0,txrssi1,txper,rxper,txopqual
04:18:D6:bb:F4:C6,Name,0,270000,270000,295650,263250,31,17,35,36,37,35,124,229,0
desired output
addr = 04:18:D6:bb:F4:C6
hname = Name
beam = 0
and so on ...
...
i would like to pair in t key value but the key is a new line form the value and put them into a Dictionary for output use this code works, but I would like to know if there is a more efficient way to do this that will skip empty values
this is what i have so far
Dictionary<string, string> INFO = new Dictionary<string, string>();
var terminal = client.RunCommand("amstainfo");
var output = terminal.Result;
string[] line = output.Split(new string[] { "\n" }, StringSplitOptions.None);
string[] KEY = line[0].Split(new string[] { "," }, StringSplitOptions.None);
string[] VALUE = line[1].Split(new string[] { "," }, StringSplitOptions.None);
int i = 0;
foreach (var ist in KEY)
{
INFO.Add(KEY[i], VALUE[i]);
i++;
}
This seems fairly straight forward like this:
var lines = text.Split(
Environment.NewLine.ToCharArray(),
StringSplitOptions.RemoveEmptyEntries);
var INFO =
lines[0].Split(',')
.Zip(lines[1].Split(','), (key, value) => new { key, value })
.Where(x => !String.IsNullOrEmpty(x.value))
.ToDictionary(x => x.key, x => x.value);
This gives:
You can include an if statement in the foreach loop to check if the value is not empty or null before adding it to the dictionary.
foreach (var ist in KEY)
{
if(!string.IsNullOrEmpty(VALUE[i]))
{
INFO.Add(KEY[i], VALUE[i]);
}
i++;
}