Parse CSV string into Array of Integers - c#

I have a text box field inputs 123,145,125 I to separate this field into an array of integers. And validate this field true or false if everything is parsed right.
CODE:
private bool chkID(out int[] val)
{
char[] delimiters = new char[] { ',' };
string[] strSplit = iconeID.Text.Split(delimiters);
int[] intArr = null;
foreach (string s in strSplit) //splits the new parsed characters
{
int tmp;
tmp = 0;
if (Int32.TryParse(s, out tmp))
{
if (intArr == null)
{
intArr = new int[1];
}
else
{
Array.Resize(ref intArr, intArr.Length + 1);
}
intArr[intArr.Length - 1] = tmp;
}
if (Int32.TryParse(iconeID.Text, out tmp))
{
iconeID.BorderColor = Color.Empty;
iconeID.BorderWidth = Unit.Empty;
tmp = int.Parse(iconeID.Text);
val = new int[1];
val[0] = tmp;
return true;
}
}
val = null;
ID.BorderColor = Color.Red;
ID.BorderWidth = 2;
return false;
}
//new Code:
private bool chkID(out int[] val) //bool satus for checkID function
{
string[] split = srtID.Text.Split(new char[1] {','});
List numbers = new List();
int parsed;
bool isOk = true;
foreach( string n in split){
if(Int32.TryParse( n , out parsed))
numbers.Add(parsed);
else
isOk = false;
}
if (isOk){
strID.BorderColor=Color.Empty;
strID.BorderWidth=Unit.Empty;
return true;
} else{
strID.BorderColor=Color.Red;
strID.BorderWidth=2;
return false;
}
return numbers.ToArray();
}

The given function seems to do too much. Here's one that answers the question implied by your title:
//int[] x = SplitStringIntoInts("1,2,3, 4, 5");
static int[] SplitStringIntoInts(string list)
{
string[] split = list.Split(new char[1] { ',' });
List<int> numbers = new List<int>();
int parsed;
foreach (string n in split)
{
if (int.TryParse(n, out parsed))
numbers.Add(parsed);
}
return numbers.ToArray();
}
EDIT (based on your comment on the question)
You've defined the three things this function needs to do. Now you just need to create methods for each. Below are my guesses for how you could implement them.
int[] ValidateIDs(int[] allIDs)
{
List<int> validIDs = new List<int>(allIDs);
//remove invalid IDs
return validIDs.ToArray();
}
void DownloadXmlData(int[] ids)
{
...
}
Now you just execute your new functions:
void CheckIconeID(string ids)
{
int[] allIDs = SplitStringIntoInts(ids);
int[] validIDs = ValidateIDs(allIDs);
DownloadXmlData(validIDs);
}

I really wanted to comment on #Austin Salonen's answer, but it didn't fit. It is a great answer for the question asked, but i wanted to expand the discussion a bit more generally on csv/int conversion part.
It's small point, not worth much debate but I would consider swapping the foreach loop for a plain for loop. You'll likely end up with simpler IL (read faster). See (http://www.codeproject.com/KB/cs/foreach.aspx, http://msdn.microsoft.com/en-us/library/ms973839.aspx [Use For Loops for String Iteration—version 1]).
I would create two methods -- one that is safe and uses TryParse and only adds the "good" values, another that is not as safe, but faster.
Proposed "safe" function (with overload in case you don't want to know the bad values)...
public static int[] SplitAsIntSafe (this string csvString) {
List<string> badVals;
return SplitAsIntSafe(csvString, ',', out badVals);
}
public static int[] SplitAsIntSafe (this string delimitedString, char splitChar, out List<string> badVals) {
int parsed;
string[] split = delimitedString.Split(new char[1] { ',' });
List<int> numbers = new List<int>();
badVals = new List<string>();
for (var i = 0; i < split.Length; i++) {
if (int.TryParse(split[i], out parsed)) {
numbers.Add(parsed);
} else {
badVals.Add(split[i]);
}
}
return numbers.ToArray();
}
Proposed "fast" function ....
public static int[] SplitAsIntFast (this string delimitedString, char splitChar) {
string[] strArray = delimitedString.Split(splitChar);
int[] intArray = new int[strArray.Length];
if(delimitedString == null) {
return new int[0];
}
for (var i = 0; i < strArray.Length; i++) {
intArray[i] = int.Parse(strArray[i]);
}
return intArray;
}
Anyway, hope this helps someone.

It might be worth your while to check out this FileHelper and also CSV Reader
Hope they will help you...
Take care,
Tom

There is a good free library for parsing CSV files: FileHelpers
using FileHelpers;
// First declare the record class
[Delimitedrecord(";")]
public class SampleType
{
public string Field1;
public int Field2;
}
public void ReadExample()
{
FileHelperEngine engine = new FileHelperEngine(typeof(SampleType));
SampleType[] records;
records = (SampleType[]) engine.ReadFile("source.txt");
// Now "records" array contains all the records in the
// sourcefile and can be acceded like this:
int sum = records[0].Field2 + records[1].Field2;
}

public bool ParseAndCheck(string source,
out IList<int> goodItems, out IList<string> badItems)
{
goodItems = new List<int>();
badItems = new List<string>();
foreach (string item in source.Split(','))
{
int temp;
if (int.TryParse(item, out temp))
goodItems.Add(temp);
else
badItems.Add(item);
}
return (badItems.Count < 1);
}

In .NET 2.0 you could write
string test = "123,14.5,125,151,1.55,477,777,888";
bool isParsingOk = true;
int[] results = Array.ConvertAll<string,int>(test.Split(','),
new Converter<string,int>(
delegate(string num)
{
int r;
isParsingOk &= int.TryParse(num, out r);
return r;
}));

This is simple and I think works pretty well. It only return valid numbers:
static int[] SplitStringIntoInts(string list)
{
int dummy;
return (from x in list.Split(',')
where int.TryParse(x.ToString(), out dummy)
select int.Parse(x.ToString())).ToArray();
}

Related

HackerRank Sparse Arrays Challenge C#

There is a collection of input strings and a collection of query strings. For each query string, determine how many times it occurs in the list of input strings. Return an array of the results.
Function Description
The function matchingStrings must return an array of integers representing the frequency of occurrence of each query string in strings.
matchingStrings has the following parameters:
string strings[n] - an array of strings to search
string queries[q] - an array of query strings
Returns
int[q]: an array of results for each query
Solution
List<string> strings = new List<string> { "4", "aba", "baba", "aba", "xzxb" };
List<string> queries = new List<string> { "3", "aba", "xzxb", "ab" };
List<int> outputList = Result.matchingStrings(strings, queries);
for (int i = 0; i < outputList.Count; i++)
{
Console.WriteLine(outputList[i]);
}
public class Result
{
public static List<int> matchingStrings(List<string> strings, List<string> queries)
{
int inputCount = 0;
Int32.TryParse(strings[0], out inputCount);
string[] input = strings.GetRange(1, strings.Count - 1).ToArray();
var stringsMap = new Dictionary<string, int>();
for (int i = 0; i < inputCount; i++)
{
if (stringsMap.ContainsKey(input[i]))
{
stringsMap[input[i]]++;
}
else
{
stringsMap.Add(input[i], 1);
}
}
int queryCount = 0;
Int32.TryParse(queries[0], out queryCount);
string[] queryStrings = queries.GetRange(1, queries.Count - 1).ToArray();
int[] output = new int[queryCount];
for (int i = 0; i < queryCount; i++)
{
if (stringsMap.ContainsKey(queryStrings[i]))
{
output[i] = stringsMap[queryStrings[i]];
}
}
List<int> outputList = output.ToList();
return outputList;
}
}
The code works fine for the given sample input in VS code. However, when it is inserted into the HackerRank online IDE, it returns no output. I do not understand what the problem could be.
This is my 100% solution in C#:
List<int> res = new List<int>();
int count=0;
for(int i=0; i<queries.Count; i++) {
count=0;
foreach(string s in strings) {
if(queries[i] == s) {
count++;
}
}
res.Add(count);
}
return res;
}
this is my solution in python
def matchingStrings(strings, queries):
hash_map=dict()
results=[]
for str in strings:
if str in hash_map:
hash_map[str]+=1
else:
hash_map[str]=1
for q in queries:
if q in hash_map:
results.append(hash_map[q])
else:
results.append(0)
return results
public static List<int> matchingStrings(List<string> strings, List<string> queries)
{
int count = 0;
List<int> countOfOccurences = new List<int>();
foreach(var query in queries){
count = strings.Where(x => x == query).Count();
countOfOccurences.Add(count);
}
return countOfOccurences;
}

C# no duplicates in array

I have a file with allot of sentences. I need to make a dictionary with the words from that file. Until now I've separated the words and sort them using Split() and Sort() methods. My problem is to make a list without duplicate words. How can I do that?
static int n = 0;
public static string[] NoDuplicate(string[] array)
{
int i;
string[] res = (string[])array.Clone();
for (i = 0; i < array.Length-1; i++)
{
if (array[i + 1] != array[i])
res[n++] = (string)array[i];
}
return res;
}
how can I do it more neat?
I don't like that method because is
initialized using Clone() and the length is too big.
You can also use HashSet beside the .Distinct() feature of LINQ:
HashSet:
This is an optimized set collection. It helps eliminates
duplicate strings or elements in an array. It is a set that hashes its
contents.
public static string[] NoDuplicate(string[] array)
{
string[] result = new HashSet<string>(array).ToArray();
return result;
}
If you want to eliminate the duplicate with case-insensitive, you can pass an IEqualityComparer argument like this:
Using HashSet:
public static string[] NoDuplicate(string[] array)
{
string[] result = new HashSet<string>(array, StringComparer.OrdinalIgnoreCase)
.ToArray();
return result;
}
Using LINQ's Distict feature:
public static string[] NoDuplicate(string[] array)
{
string[] result = array.Distinct(StringComparer.OrdinalIgnoreCase)
.ToArray();
return result;
}
Try this:
private static string[] NoDuplicate(string[] inputArray)
{
var result = inputArray.Distinct().ToArray();
return result;
}
Instead of dictionary create a trie of words.
At each level keep a count of sameWord if it repeats. This way you can avoid using too much space and it will be faster to search any word O(log(n))
where n is number of distinct words
public class WordList {
private int sameWord = 0;
String name = "";
WordList [] child = new WordList[26];
public void add( String s, WordList c, int index )
{
sameWord++;
if(index > 0)
{
name += ""+s.charAt(index-1);
}
if(index == s.length())
{
return;
}
if(c.child[s.charAt(index)-'a'] ==null)
{
c.child[s.charAt(index)-'a'] = new WordList();
}
add(s,c.child[s.charAt(index)-'a'],index+1);
}
public static WordList findChar(char c)
{
return child[(int)(c-'a')];
}
}
You can try below solution:
private static string[] NoDuplicate(string[] inputArray)
{
List<string> stringList = new List<string>();
foreach (string s in inputArray)
{
if (!stringList.Contains(s))
{
stringList.Add(s);
}
}
return stringList.ToArray();
}

How to iterate lists with different lengths to find all permutations?

This one should not be too hard but my mind seems to be having a stack overflow (huehue). I have a series of Lists and I want to find all permutations they can be ordered in. All of the lists have different lengths.
For example:
List 1: 1
List 2: 1, 2
All permutations would be:
1, 1
1, 2
In my case I don't switch the numbers around. (For example 2, 1)
What is the easiest way to write this?
I can't say if the following is the easiest way, but IMO it's the most efficient way. It's basically a generalized version of the my answer to the Looking at each combination in jagged array:
public static class Algorithms
{
public static IEnumerable<T[]> GenerateCombinations<T>(this IReadOnlyList<IReadOnlyList<T>> input)
{
var result = new T[input.Count];
var indices = new int[input.Count];
for (int pos = 0, index = 0; ;)
{
for (; pos < result.Length; pos++, index = 0)
{
indices[pos] = index;
result[pos] = input[pos][index];
}
yield return result;
do
{
if (pos == 0) yield break;
index = indices[--pos] + 1;
}
while (index >= input[pos].Count);
}
}
}
You can see the explanation in the linked answer (shortly it's emulating nested loops). Also since for performace reasons it yields the internal buffer w/o cloning it, you need to clone it if you want store the result for later processing.
Sample usage:
var list1 = new List<int> { 1 };
var list2 = new List<int> { 1, 2 };
var lists = new[] { list1, list2 };
// Non caching usage
foreach (var combination in lists.GenerateCombinations())
{
// do something with the combination
}
// Caching usage
var combinations = lists.GenerateCombinations().Select(c => c.ToList()).ToList();
UPDATE: The GenerateCombinations is a standard C# iterator method, and the implementation basically emulates N nested loops (where N is the input.Count) like this (in pseudo code):
for (int i0 = 0; i0 < input[0].Count; i0++)
for (int i1 = 0; i1 < input[1].Count; i1++)
for (int i2 = 0; i2 < input[2].Count; i2++)
...
for (int iN-1 = 0; iN-1 < input[N-1].Count; iN-1++)
yield { input[0][i0], input[1][i1], input[2][i2], ..., input[N-1][iN-1] }
or showing it differently:
for (indices[0] = 0; indices[0] < input[0].Count; indices[0]++)
{
result[0] = input[0][indices[0]];
for (indices[1] = 0; indices[1] < input[1].Count; indices[1]++)
{
result[1] = input[1][indices[1]];
// ...
for (indices[N-1] = 0; indices[N-1] < input[N-1].Count; indices[N-1]++)
{
result[N-1] = input[N-1][indices[N-1]];
yield return result;
}
}
}
Nested loops:
List<int> listA = (whatever), listB = (whatever);
var answers = new List<Tuple<int,int>>;
for(int a in listA)
for(int b in listB)
answers.add(Tuple.create(a,b));
// do whatever with answers
Try this:
Func<IEnumerable<string>, IEnumerable<string>> combine = null;
combine = xs =>
xs.Skip(1).Any()
? xs.First().SelectMany(x => combine(xs.Skip(1)), (x, y) => String.Format("{0}{1}", x, y))
: xs.First().Select(x => x.ToString());
var strings = new [] { "AB", "12", "$%" };
foreach (var x in combine(strings))
{
Console.WriteLine(x);
}
That gives me:
A1$
A1%
A2$
A2%
B1$
B1%
B2$
B2%
I made the following IEnumerable<IEnumerable<TValue>> class to solve this problem which allows use of generic IEnumerable's and whose enumerator returns all permutations of the values, one from each inner list. It can be conventiently used directly in a foreach loop.
It's a variant of Michael Liu's answer to IEnumerable and Recursion using yield return
I've modified it to return lists with the permutations instead of the single values.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Permutation
{
public class ListOfListsPermuter<TValue> : IEnumerable<IEnumerable<TValue>>
{
private int count;
private IEnumerable<TValue>[] listOfLists;
public ListOfListsPermuter(IEnumerable<IEnumerable<TValue>> listOfLists_)
{
if (object.ReferenceEquals(listOfLists_, null))
{
throw new ArgumentNullException(nameof(listOfLists_));
}
listOfLists =listOfLists_.ToArray();
count = listOfLists.Count();
for (int i = 0; i < count; i++)
{
if (object.ReferenceEquals(listOfLists[i], null))
{
throw new NullReferenceException(string.Format("{0}[{1}] is null.", nameof(listOfLists_), i));
}
}
}
// A variant of Michael Liu's answer in StackOverflow
// https://stackoverflow.com/questions/2055927/ienumerable-and-recursion-using-yield-return
public IEnumerator<IEnumerable<TValue>> GetEnumerator()
{
TValue[] currentList = new TValue[count];
int level = 0;
var enumerators = new Stack<IEnumerator<TValue>>();
IEnumerator<TValue> enumerator = listOfLists[level].GetEnumerator();
try
{
while (true)
{
if (enumerator.MoveNext())
{
currentList[level] = enumerator.Current;
level++;
if (level >= count)
{
level--;
yield return currentList;
}
else
{
enumerators.Push(enumerator);
enumerator = listOfLists[level].GetEnumerator();
}
}
else
{
if (level == 0)
{
yield break;
}
else
{
enumerator.Dispose();
enumerator = enumerators.Pop();
level--;
}
}
}
}
finally
{
// Clean up in case of an exception.
enumerator?.Dispose();
while (enumerators.Count > 0)
{
enumerator = enumerators.Pop();
enumerator.Dispose();
}
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
You can use it directly in a foreach like this:
public static void Main(string[] args)
{
var listOfLists = new List<List<string>>()
{
{ new List<string>() { "A", "B" } },
{ new List<string>() { "C", "D" } }
};
var permuter = new ListOfListsPermuter<string>(listOfLists);
foreach (IEnumerable<string> item in permuter)
{
Console.WriteLine("{ \"" + string.Join("\", \"", item) + "\" }");
}
}
The output:
{ "A", "C" }
{ "A", "D" }
{ "B", "C" }
{ "B", "D" }

c# lists not storing values after using int.TryParse

I have the following code below that reads in text file and searches it for integers. I am using 'int.TryParse' to do this but it is not storing the integer values in the lists after it has run, just wondering if you could tell me what is wrong with this code. Thanks.
namespace AccessErrorFile
{
class Program
{
static void Main(string[] args)
{
List<int> plans = new List<int>();
List<int> events = new List<int>();
using (var reader = new StreamReader(#"D:\Temp\AccessEmail.txt"))
try
{
string line;
while ((line = reader.ReadLine()) != null)
{
//split the line
string[] parts = line.Split(new[] { "Event" }, StringSplitOptions.None);
//get valid integers
plans.Add(GetInt(parts[0].Split(' ', '\'')));
events.Add(GetInt(parts[1].Split(' ', '\'')));
}
}
catch (System.Exception ex)
{
Console.WriteLine("Error" + ex.Message);
}
//print the elements in the lists
foreach (int x in plans)
{
Console.WriteLine(x);
}
foreach (int y in events)
{
Console.WriteLine(y);
}
//print the number of elements in the lists
Console.WriteLine(plans.Count);
Console.WriteLine(events.Count);
Console.ReadLine();
}
public static int GetInt(string[] a)
{
int i = 0;
foreach (string s in a)
int.TryParse(s, out i);
return i;
}
}
}
your problem is
public static int GetInt(string[] a)
{
int i = 0;
foreach (string s in a) //HERE
int.TryParse(s, out i); //AND HERE
return i;
}
you are parsing in the loop, so the return i statement returns basically the last s of iteration, which, most probably is not a number, so i=0.
If you want to add all numbers from the string to array of ints, you can do something like:
IEnumerable<int> GetNumbersFromList(string[] s) {
foreach(var str in s) {
int val;
if(int.TryParse(str, out val))
yield return val;
}
}
and after
plans.AddRange(GetNumbersFromList(parts));
Just a basic idea, naturally, you have to fit it to your needs.

How to convert a list with splitted strings to a possible value sets?

I need to implement a module which will convert a List which with splitted string values to a possible value sets.
For Example
consider the list contains following values
1
1,2
3
4
5
The module should convert the above list to list of possible value sets
1,2,3,4,5
1,1,3,4,5
thanks in advance
This will do it, although it will return your example in the opposite order:
static IEnumerable<string> Permutations(
IEnumerable<string> input,
char separator)
{
var sepAsString = separator.ToString();
var enumerators = input
.Select(s => s.Split(separator).GetEnumerator())
.ToArray();
if (!enumerators.All(e => e.MoveNext())) yield break;
while (true)
{
yield return String.Join(sepAsString, enumerators.Select(e => e.Current));
if (enumerators.Reverse().All(e => {
bool finished = !e.MoveNext();
if (finished)
{
e.Reset();
e.MoveNext();
}
return finished;
}))
yield break;
}
}
Usage:
var list = new[] { "1", "1,2", "3", "4", "5" }.ToList();
var perms = Permutations(list, ',').ToList();
Rawling's answer is pretty solid, but i don't find it easy to read and understand. Here's another way, using less Linq.
private List<string> Process(IEnumerable<string> input)
{
List<string> data = new List<string>();
int preExpandCount = 0, offset = 0;
foreach (string inputItem in input)
{
List<string> splitItems = inputItem.Split(',').ToList();
if (data.Count > 0)
preExpandCount = ExpandList(data, splitItems.Count - 1);
offset = 0;
foreach (string splitItem in splitItems)
{
if (preExpandCount == 0)
data.Add(splitItem);
else
{
for (int i = 0; i < preExpandCount; i++)
data[i + offset] = String.Format("{0},{1}", data[i + offset], splitItem);
offset += preExpandCount;
}
}
}
return data.OrderBy(e => e).ToList();
}
private int ExpandList(List<string> existing, int count)
{
int existingCount = existing.Count;
for (int i = 0; i < count; i++)
existing.AddRange(existing.Take(existingCount).ToList());
return existingCount;
}

Categories

Resources