The exception I get is:
The type initializer for MyNamespace.Program threw an exception
The inner exception says
Message: Value cannot be null. Parameter name: collection
Source: ... HashSet ...
This leads me to believe the error is occuring on the line indicated below...
class Program
{
public static IEnumerable<char> WordCharacters = ExpandCharacterSet("A-Za-z0-9_");
public static IEnumerable<char> NonWordCharacters = ExpandCharacterSet("^A-Za-z0-9_");
public static IEnumerable<char> SpaceCharacters = ExpandCharacterSet(" \f\n\r\t\v");
public static IEnumerable<char> NonSpaceCharacters = ExpandCharacterSet("^ \f\n\r\t\v");
public static IEnumerable<char> DigitCharacters = ExpandCharacterSet("0-9");
public static IEnumerable<char> NonDigitCharacters = ExpandCharacterSet("^0-9");
public static IEnumerable<char> WildCharacters = ExpandCharacterSet("^\n");
public static IEnumerable<char> AllCharacters = Enumerable.Range(0, 256).Select(Convert.ToChar).Where(c => !char.IsControl(c));
public static IEnumerable<char> ExpandCharacterSet(string set)
{
if (set.Length == 0)
return "";
var sb = new StringBuilder();
int start = 0;
bool invertSet = false;
if (set[0] == '[' && set[set.Length - 1] == ']')
set = set.Substring(1, set.Length - 2);
if (set[0] == '^')
{
invertSet = true;
set = set.Substring(1);
}
set = Regex.Unescape(set);
foreach (Match m in Regex.Matches(set, ".-.|."))
{
if (m.Value.Length == 1)
sb.Append(m.Value);
else
{
if (m.Value[0] > m.Value[2]) throw new ArgumentException("Invalid character set.");
for (char c = m.Value[0]; c <= m.Value[2]; ++c)
sb.Append(c);
}
}
if (!invertSet) return sb.ToString();
var A = new HashSet<char>(AllCharacters); // <---- change this to "ABC" and the error goes away
var B = new HashSet<char>(sb.ToString());
A.ExceptWith(B);
return A;
}
static void Main(string[] args)
{
}
}
But I don't know why. When I print the chars,
Console.WriteLine(string.Concat(AllChars));
It prints every character as expected. So why does HashSet think it's null?
I'm guessing that ExpandCharacterSet is being used to initialize another static field. There's no guarantee on the order in which two static fields will be initialized, and so presuably, it's trying to initialize the other field before it initializes AllChars.
Try moving the assignments into an explicit static constructor, with the correct initialization order.
e.g if your current code has:
public static IEnumerable<char> AllChars = Enumerable.Range(0, 256).Select(Convert.ToChar).Where(c => !char.IsControl(c));
public static IEnumerable<char> Expanded = ExpandCharacterSet(...);
Make it instead:
public static IEnumerable<char> AllChars;
public static IEnumerable<char> Expanded;
static <ClassName> {
AllChars = Enumerable.Range(0, 256).Select(Convert.ToChar).Where(c => !char.IsControl(c));
Expanded = ExpandCharacterSet(...);
}
I think, AllChars is being set to null from some other part of your code, because the above two methods seems to be working fine.
Can you provide some more details of implementation.
I'm not getting any except on based on the following two lines of code. Where is the line of code that is throwing the exception?
public static IEnumerable<char> AllChars = Enumerable.Range(0, 256)
.Select(Convert.ToChar)
.Where(c => !char.IsControl(c));
var A = new HashSet<char>(AllChars);
Related
If I write:
var type = typeof(List<string>);
Console.WriteLine(type.Name);
It will write:
List`1
I want it to write just:
List
How can I do that?
Is there a smarter way to do it without having to use Substring or similar string manipulation functions?
No, it makes perfect sense for it to include the generic arity in the name - because it's part of what makes the name unique (along with assembly and namespace, of course).
Put it this way: System.Nullable and System.Nullable<T> are very different types. It's not expected that you'd want to confuse the two... so if you want to lose information, you're going to have to work to do it. It's not very hard, of course, and can be put in a helper method:
public static string GetNameWithoutGenericArity(this Type t)
{
string name = t.Name;
int index = name.IndexOf('`');
return index == -1 ? name : name.Substring(0, index);
}
Then:
var type = typeof(List<string>);
Console.WriteLine(type.GetNameWithoutGenericArity());
No, it doesn't, because the "generic-type-string" is part of the name of type.
If someone is interested, I created some extensionmethods for this problem that create a more "readable" string
it produces something like
List[string]
outer.inner[other.whatever]
IEnumerable[T0]
Dictionary[string:int]
Test here
public static class TypeEx
{
public static string GetTypeName(this Type type)
{
if (type == null)
throw new ArgumentNullException(nameof(type));
if (!type.IsGenericType)
return type.GetNestedTypeName();
StringBuilder stringBuilder = new StringBuilder();
_buildClassNameRecursiv(type, stringBuilder);
return stringBuilder.ToString();
}
private static void _buildClassNameRecursiv(Type type, StringBuilder classNameBuilder, int genericParameterIndex = 0)
{
if (type.IsGenericParameter)
classNameBuilder.AppendFormat("T{0}", genericParameterIndex + 1);
else if (type.IsGenericType)
{
classNameBuilder.Append(GetNestedTypeName(type) + "[");
int subIndex = 0;
foreach (Type genericTypeArgument in type.GetGenericArguments())
{
if (subIndex > 0)
classNameBuilder.Append(":");
_buildClassNameRecursiv(genericTypeArgument, classNameBuilder, subIndex++);
}
classNameBuilder.Append("]");
}
else
classNameBuilder.Append(type.GetNestedTypeName());
}
public static string GetNestedTypeName(this Type type)
{
if (type == null)
throw new ArgumentNullException(nameof(type));
if (!type.IsNested)
return type.Name;
StringBuilder nestedName = new StringBuilder();
while(type != null)
{
if(nestedName.Length>0)
nestedName.Insert(0,'.');
nestedName.Insert(0, _getTypeName(type));
type = type.DeclaringType;
}
return nestedName.ToString();
}
private static string _getTypeName(Type type)
{
return type.IsGenericType ? type.Name.Split('`')[0]: type.Name;
}
}
static void Main(string[] args)
{
Console.WriteLine(WhatIsMyType<IEnumerable<string>>());
Console.WriteLine(WhatIsMyType<List<int>>());
Console.WriteLine(WhatIsMyType<IList<int>>());
Console.WriteLine(WhatIsMyType<List<ContentBlob>>());
Console.WriteLine(WhatIsMyType<int[]>());
Console.WriteLine(WhatIsMyType<ContentBlob>());
Console.WriteLine(WhatIsMyType<Dictionary<string, Dictionary<int, int>>>());
}
public static string WhatIsMyType<T>()
{
return typeof(T).NameWithGenerics();
}
public static string NameWithGenerics(this Type type)
{
if (type == null)
throw new ArgumentNullException(nameof(type));
if (type.IsArray)
return $"{type.GetElementType()?.Name}[]";
if (!type.IsGenericType)
return type.Name;
var name = type.GetGenericTypeDefinition().Name;
var index = name.IndexOf('`');
var newName = index == -1 ? name : name.Substring(0, index);
var list = type.GetGenericArguments().Select(NameWithGenerics).ToList();
return $"{newName}<{string.Join(",", list)}>";
}
Example output:
IEnumerable<String>
List<Int32>
IList<Int32>
List<ContentBlob>
Int32[]
ContentBlob
Dictionary<String,Dictionary<Int32,Int32>>
Here's the code from this answer inside a static class and namespace for easier copy-and-pasting.
Also, there's another extension method to get the type its namespace.
using System;
namespace TODO
{
public static class TypeExtensions
{
/// <summary>
/// From: https://stackoverflow.com/a/6386234/569302
/// </summary>
public static string GetNameWithoutGenericArity(this Type t)
{
string name = t.Name;
int index = name.IndexOf('`');
return index == -1 ? name : name.Substring(0, index);
}
public static string GetFullNameWithoutGenericArity(this Type t)
{
var result = $"{t.Namespace}.{t.GetNameWithoutGenericArity()}";
return result;
}
}
}
The easiest way I can think of as of C#6(I think) you can do the following:
public static void Main(string[] args)
{
Console.WriteLine(nameof(List<int>));
Console.WriteLine(nameof(Dictionary<int, int>));
}
This will print:
List
Dictionary
So, I have a C# string input which can be either "ABCD12345678" or "ABCD1234" or "ABCD1233456v1" or "ABCD1233456v2" or "AVVV1233456v334" or "ABVV1233456V4".
I need to manipulate and remove the last may or may not be occurring "v"/"V" and get the result like :
"ABCD1233456"
"ABVV1233456"
"AVVV1233456"
Please help. If I use substring straightforward it works for only those where "v" occurs but throws exception for those where it doesn't occur.
It's a little confusing when you say at the end because the v isn't really at the end...
Anyway, what about Regex?
public static class VRemover
{
public static string Process(string input)
{
var regex = new Regex(#"(?'util'[a-z]+\d+)(v\d*)?", RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
return regex.IsMatch(input)
? regex.Match(input).Groups["util"].Value
: input;
}
}
You can validate with this test (NUnit):
[TestFixture]
public class VRemoverTests
{
[Test]
public void Test()
{
var inputs = new[]
{
"ABCD12345678",
"ABCD1234",
"ABCD1233456v1",
"ABCD1233456v2",
"AVVV1233456v334",
"ABVV1233456V4"
};
var expecteds = new[]
{
"ABCD12345678",
"ABCD1234",
"ABCD1233456",
"ABCD1233456",
"AVVV1233456",
"ABVV1233456"
};
for (var i = 0; i < inputs.Length; i++)
{
var actual = VRemover.Process(inputs[i]);
Assert.AreEqual(expecteds[i], actual);
}
}
}
private static string RemoveString (string input)
{
var indexOf = input.LastIndexOf("v", StringComparison.OrdinalIgnoreCase);
if (indexOf < 0)
return input;
return input.Substring(0, indexOf);
}
private string ReplaceLastV(string input)
{
if (input.IndexOf("v", StringComparison.OrdinalIgnoreCase) > 0)
{
int lastIndexV = input.LastIndexOf("v", StringComparison.OrdinalIgnoreCase);
return input.Substring(0, lastIndexV);
}
return input;
}
I am having a problem with a custom struct and overloading linq's except method to remove duplicates.
My struct is as follows:
public struct hashedFile
{
string _fileString;
byte[] _fileHash;
public hashedFile(string fileString, byte[] fileHash)
{
this._fileString = fileString;
this._fileHash = fileHash;
}
public string FileString { get { return _fileString; } }
public byte[] FileHash { get { return _fileHash; } }
}
Now, the following code works fine:
public static void test2()
{
List<hashedFile> list1 = new List<hashedFile>();
List<hashedFile> list2 = new List<hashedFile>();
hashedFile one = new hashedFile("test1", BitConverter.GetBytes(1));
hashedFile two = new hashedFile("test2", BitConverter.GetBytes(2));
hashedFile three = new hashedFile("test3", BitConverter.GetBytes(3));
hashedFile threeA = new hashedFile("test3", BitConverter.GetBytes(4));
hashedFile four = new hashedFile("test4", BitConverter.GetBytes(4));
list1.Add(one);
list1.Add(two);
list1.Add(threeA);
list1.Add(four);
list2.Add(one);
list2.Add(two);
list2.Add(three);
List<hashedFile> diff = list1.Except(list2).ToList();
foreach (hashedFile h in diff)
{
MessageBox.Show(h.FileString + Environment.NewLine + h.FileHash[0].ToString("x2"));
}
}
This code shows "threeA" and "four" just fine. But if I do the following.
public static List<hashedFile> list1(var stuff1)
{
//Generate a List here and return it
}
public static List<hashedFile> list2(var stuff2)
{
//Generate a List here and return it
}
List<hashedFile> diff = list1.except(list2);
"diff" becomes an exact copy of "list1". I should also mention that I am sending a byte array from ComputeHash from System.Security.Cryptography.MD5 to the byte fileHash in the list generations.
Any ideas on how to overload either the Except or GetHashCode method for linq to successfully exclude the duplicate values from list2?
I'd really appreciate it! Thanks!
~MrFreeman
EDIT: Here was how I was originally trying to use List<hashedFile> diff = newList.Except(oldList, new hashedFileComparer()).ToList();
class hashedFileComparer : IEqualityComparer<hashedFile>
{
public bool Equals(hashedFile x, hashedFile y)
{
if (Object.ReferenceEquals(x, y)) return true;
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
return x.FileString == y.FileString && x.FileHash == y.FileHash;
}
public int GetHashCode(hashedFile Hashedfile)
{
if (Object.ReferenceEquals(Hashedfile, null)) return 0;
int hashFileString = Hashedfile.FileString == null ? 0 : Hashedfile.FileString.GetHashCode();
int hashFileHash = Hashedfile.FileHash.GetHashCode();
int returnVal = hashFileString ^ hashFileHash;
if (Hashedfile.FileString.Contains("blankmusic") == true)
{
Console.WriteLine(returnVal.ToString());
}
return returnVal;
}
}
If you want the type to handle its own comparisons in Except the interface you need is IEquatable. The IEqualityComparer interface is to have another type handle the comparisons so it can be passed into Except as an overload.
This achieves what you want (assuming you wanted both file string and hash compared).
public struct hashedFile : IEquatable<hashedFile>
{
string _fileString;
byte[] _fileHash;
public hashedFile(string fileString, byte[] fileHash)
{
this._fileString = fileString;
this._fileHash = fileHash;
}
public string FileString { get { return _fileString; } }
public byte[] FileHash { get { return _fileHash; } }
public bool Equals(hashedFile other)
{
return _fileString == other._fileString && _fileHash.SequenceEqual(other._fileHash);
}
}
Here is an example in a working console application.
public class Program
{
public struct hashedFile : IEquatable<hashedFile>
{
string _fileString;
byte[] _fileHash;
public hashedFile(string fileString, byte[] fileHash)
{
this._fileString = fileString;
this._fileHash = fileHash;
}
public string FileString { get { return _fileString; } }
public byte[] FileHash { get { return _fileHash; } }
public bool Equals(hashedFile other)
{
return _fileString == other._fileString && _fileHash.SequenceEqual(other._fileHash);
}
}
public static void Main(string[] args)
{
List<hashedFile> list1 = GetList1();
List<hashedFile> list2 = GetList2();
List<hashedFile> diff = list1.Except(list2).ToList();
foreach (hashedFile h in diff)
{
Console.WriteLine(h.FileString + Environment.NewLine + h.FileHash[0].ToString("x2"));
}
Console.ReadLine();
}
private static List<hashedFile> GetList1()
{
hashedFile one = new hashedFile("test1", BitConverter.GetBytes(1));
hashedFile two = new hashedFile("test2", BitConverter.GetBytes(2));
hashedFile threeA = new hashedFile("test3", BitConverter.GetBytes(4));
hashedFile four = new hashedFile("test4", BitConverter.GetBytes(4));
var list1 = new List<hashedFile>();
list1.Add(one);
list1.Add(two);
list1.Add(threeA);
list1.Add(four);
return list1;
}
private static List<hashedFile> GetList2()
{
hashedFile one = new hashedFile("test1", BitConverter.GetBytes(1));
hashedFile two = new hashedFile("test2", BitConverter.GetBytes(2));
hashedFile three = new hashedFile("test3", BitConverter.GetBytes(3));
var list1 = new List<hashedFile>();
list1.Add(one);
list1.Add(two);
list1.Add(three);
return list1;
}
}
This is becoming quite large but I will continue there is an issue with above implementation if hashedFile is a class not a struct (and sometimes when a stuct maybe version depdendant). Except uses an internal Set class the relevant part of that which is problematic is that it compares the hash codes and only if they are equal does it then use the comparer to check equality.
int hashCode = this.InternalGetHashCode(value);
for (int i = this.buckets[hashCode % this.buckets.Length] - 1; i >= 0; i = this.slots[i].next)
{
if ((this.slots[i].hashCode == hashCode) && this.comparer.Equals(this.slots[i].value, value))
{
return true;
}
}
The fix for this depending on performance requirements is you can just return a 0 hash code. This means the comparer will always be used.
public override int GetHashCode()
{
return 0;
}
The other option is to generate a proper hash code this matters sooner than I expected the difference for 500 items is 7ms vs 1ms and for 5000 items is 650ms vs 13ms. So probably best to go with a proper hash code. byte array hash code function taken from https://stackoverflow.com/a/7244316/1002621
public override int GetHashCode()
{
var hashCode = 0;
var bytes = _fileHash.Union(Encoding.UTF8.GetBytes(_fileString)).ToArray();
for (var i = 0; i < bytes.Length; i++)
hashCode = (hashCode << 3) | (hashCode >> (29)) ^ bytes[i]; // Rotate by 3 bits and XOR the new value.
return hashCode;
}
I'm building this simple program but i'm having some problems with it. I encapsulated an array into a class and filled it up with random numbers. When in Main i want to evaluate it using Console.WriteLine(), it gives an error:
Cannot apply indexing with [] to an expression of type 'method group'.
What did i do wrong?
class Program
{
public static void Main(string[] args)
{
Arrays randomArray = new Arrays();
Console.WriteLine("Please type in an integer!");
int encryptionKey = Convert.ToInt32(Console.ReadLine());
randomArray.MyArray.SetValue(encryptionKey, 0);
int i = 0;
while (i < 256)
{
Console.WriteLine(i + " " + randomArray.MyArray[i]);
i++;
}
Console.ReadLine();
}
public static int[] MakeArray()
{
Random rnd = new Random();
var value = Enumerable.Range(0, 256)
.Select(x => new { val = x, order = rnd.Next() })
.OrderBy(i => i.order)
.Select(x => x.val)
.ToArray();
return value;
}
}
public class Arrays
{
private int[] _myArray;
public int[] MyArray
{
get
{
return _myArray;
}
set
{
_myArray = Program.MakeArray();
}
}
}
first of all, in line
randomArray.MyArray.SetValue(encryptionKey, 0);
program gives you an exception (null reference) becuase in this line the get section of MyArray will executed and returns null to caller. so you must set your array (MyArray) value in the constructor of class (Arrays) and this section is wrong in design by my opinion
set
{
_myArray = Program.MakeArray();
}
try this
public class Arrays
{
public int[] _myArray;
public Arrays() {
MyArray = Program.MakeArray();
}
public int[] MyArray
{
get; set;
}
}
this will fix the problem
string[] arr = { "abcdefXXX872358", "abcdef200X8XXX58", "abcdef200X872359", "6T1XXXXXXXXXXXX11", "7AbcdeHA30XXX541", "7AbcdeHA30XXX691" };
how can I get distinct numbers from above where first 6 character must be distinct
result would be
abcdefXXX872358
6T1XXXXXXXXXXXX11
7AbcdeHA30XXX541
I try something like this
var dist = (from c in arr
select c).Select(a => a.Substring(0, 5)).Distinct();
which gives me first 5 character but I want whole string
Group on the first characters, and get the first string in each group:
IEnumerable<string> firstInGroup =
arr
.GroupBy(s => s.Substring(0, 6))
.Select(g => g.First());
I think the best method would be to implement an IEqualityComparer, as is hinted by the overload on List.Distinct()
public class firstXCharsComparer : IEqualityComparer<string>
{
private int numChars;
public firstXCharsComparer(int numChars)
{
this.numChars = numChars;
}
public bool Equals(string x, string y)
{
return x.Substring(0, numChars) == y.Substring(0, numChars);
}
public int GetHashCode(string obj)
{
return obj.Substring(0, numChars).GetHashCode();
}
}
static void Main(string[] args)
{
string[] arr = { "abcdefXXX872358", "abcdef200X8XXX58", "abcdef200X872359", "6T1XXXXXXXXXXXX11", "7AbcdeHA30XXX541", "7AbcdeHA30XXX691" };
var result = arr.ToList().Distinct(new firstXCharsComparer(6));
result.Count();
}