C# List not comparing with equals operator - c#

I am comparing two lists in C#. Here is the basic code
List<string> expectedTabs = new List<string>() { "Batch", "Card Services", "ReportingXXXXX" };
List<string> actualTabs = new List<string>() { "Batch", "Card Services", "Reporting" };
string [] text = new string[actualTabs.Count];
int i = 0;
foreach (IWebElement element in actualTabs)
{
text[i++] = element;
Console.WriteLine("Tab Text : " + text[i - 1]);
}
for(int x = 0; x < actualTabs.Count; x++)
{
Assert.IsTrue(expectedTabs.Count == actualTabs.Count); //this gives equal count
Console.WriteLine(expectedTabs[x] + " :: " + actualTabs[x]);
expectedTabs[x].Equals(actualTabs[x]); //Gives wrong result here
Console.WriteLine(expectedTabs.GetType()); //returns type as collection.list
}
Now the equal should return false when comparing the last element [ReportingXXXXX and Reporting] in both the lists, but it just gives the result as equal. I am not sure if I need to use something else here.

reducing your code to what I think is the relevant bits...
var expectedTabs = new List<string>() { "Batch", "Card Services", "ReportingXXXXX" };
var actualTabs = new List<string>() { "Batch", "Card Services", "Reporting" };
for (var x = 0; x < actualTabs.Count; x++)
{
var equal = expectedTabs[x].Equals(actualTabs[x]); //Gives wrong result here
Console.WriteLine(equal);
}
This produces
True
True
False
Where are you seeing the wrong result?
Your code / comparison works fine.

Related

Why is the .Clear() function clearing the wrong list?

public void ConvertMoves()
{
for (int i = 0; i < maxDirections; i++)
{
Debug.Log("gimme tsMoves "+tSpossibleMoves[i].Count + " from " + this);
possibleAttacks[i] = tSpossibleAttacks[i];
possibleAttacksInactive[i] = tSpossibleAttacksInactive[i];
possibleAttackIndicators[i] = tSpossibleAttackIndicators[i];
possibleMoves[i] = tSpossibleMoves[i];
Debug.Log("Gimme moves(1) " + possibleMoves[i].Count + " from " + this);
}
for (int i = 0; i < maxDirections; i++)
{
tSpossibleAttacks[i].Clear();
tSpossibleAttacksInactive[i].Clear();
tSpossibleAttackIndicators[i].Clear();
tSpossibleMoves[i].Clear();
Debug.Log("Gimme moves(2) " + possibleMoves[i].Count + " from " + this);
}
}
so the Debug Log reports the following:
gimme tsMoves 2 from JeanArc(Clone) (JeanArc)
Gimme moves(1) 2 from JeanArc(Clone) (JeanArc)
sofar everything is doing fine but then...
Gimme moves(2) 0 from JeanArc(Clone) (JeanArc)
why does it clear the moves of whole different List variable ?
This doesn't create a copy of the list item:
possibleAttacks[i] = tSpossibleAttacks[i]
It simply copies the reference to the same object into a second variable, so possibleAttacks[i] and tSpossibleAttacks[i] now both point to the same item in memory. Think of it like having two credit cards to access one bank account.
You can read more about reference types here in Microsoft's docs.
As Heinzi pointed out in the comment below, you can copy your item (as it's a list) by calling:
possibleAttacks[i] = tSpossibleAttacks[i].ToList();
By the way, if you just want to assign tSpossibleAttacks[i] and then reset it, you could also just do this:
possibleAttacks[i] = tSpossibleAttacks[i];
tSpossibleAttacks[i] = new List<your_type_name_here>(); // this will overwrite the reference held by `tSpossibleAttacks[i]`.
Note that if your list contains reference types, you have a similar problem within the list, for example:
public class Test
{
public string Name { get; set; }
}
List<Test> list1 = new List<Test>();
list1.Add(new Test() { Name = "John" });
List<Test> list2 = list1.ToList();
Console.WriteLine(list1[0].Name); // John
Console.WriteLine(list2[0].Name); // John
list2[0].Name = "Fred";
Console.WriteLine(list1[0].Name); // Fred
Console.WriteLine(list2[0].Name); // Fred
So I'd recommend reading up on value types vs reference types and how references work in C#.
What #John said. You need to copy the lists.
for (int i = 0; i < maxDirections; i++)
{
Debug.Log("gimme tsMoves "+tSpossibleMoves[i].Count + " from " + this);
possibleAttacks[i] = tSpossibleAttacks[i];
tSpossibleAttacks[i] = new List<T>;
possibleAttacksInactive[i] = tSpossibleAttacksInactive[i];
tSpossibleAttacksInactive[i] = new List<U>();
possibleAttackIndicators[i] = tSpossibleAttackIndicators[i];
tSpossibleAttackIndicators[i] = new List<V>();
possibleMoves[i] = tSpossibleMoves[i];
tSpossibleMoves[i] = new List<Z>();
Debug.Log($"Gimme moves(1), i={i}: {possibleMoves[i].Count} from {this}");
Debug.Log($"Gimme moves(2) i={i}: {tpossibleMoves[i].Count} from {this}");
}
Example:
var l1 = new List<string>();
List<string> l2;
l1.Add("One");
l1.Add("Two");
l2 = l1;
l1 = new List<string>();
l1.Add("Three");
Console.WriteLine("L1:");
foreach (var elem in l1)
{
Console.WriteLine(elem);
}
Console.WriteLine("L2:");
foreach (var elem in l2)
{
Console.WriteLine(elem);
}
This prints:
L1:
Three
L2:
One
Two

Is there an equivalent of bulk contains?

Is there some utility to check whether a sequence contains multiple elements instead of using Contains repeatedly?
List<string> containter = new List<string>();
for (int i = 0; i < 10; i++)
{
containter.Add("string #" + i);
}
if (containter.Contains("string #2") && //Is it possible to replace this with one call passing two strings to improve efficiency
containter.Contains("string #6"))
{
//Do Something
}
According to the updated question, I've modified my answer:
List<string> containter = new List<string>();
for (int i = 0; i < 10; i++)
{
containter.Add("string #" + i);
}
//define a checklist
List<string> checkList = new List<string> { "string #2", "string #6" };
//we're in, if every item in checkList is present in container
if (!checkList.Except(containter).Any())
{
Console.WriteLine("true");
}
Still you may use Any. But in this context it would be nice to use Except method.
If every item in checkList is present in the container the resulting sequence would contain no elements, so Any should return false.
I am assuming you want to compare two sequences, and want to know if one sequence contains all of the elements in another sequence.
var outer = new List<String>() { "1", "2", "3" };
var inner = new List<String>() { "1", "2" };
bool outerContainsAllInnerElements = inner.TrueForAll(i => outer.Contains(i));
Alternatively, you could use Intersect(), but that will project your items into a new sequence when you attempt to get its count. If that's what you want, great, but if you don't need to know which elements intersect, then TrueForAll() would save that overhead.
var outer = new List<String>() { "1", "2", "3" };
var inner = new List<String>() { "1", "2" };
var elementsInBoth = outer.Intersect(inner);
bool outerContainsAllInnerElements = (elementsInBoth.Count() == inner.Count());
Any:
string s = "I am a string";
string[] check = { "is", "my" };
Console.WriteLine(check.Any(x => s.Contains(x))); // False
s = "This is a string";
Console.WriteLine(check.Any(x => s.Contains(x))); // True
s = "my string";
Console.WriteLine(check.Any(x => s.Contains(x))); // True

How to check whether a word is composed of other strings in an array

I want to check whether a string is built from another two strings within a given string set.
For example, given the following array:
var arr = new string[] { "b", "at", "bat", "ct", "ll", "ball", "ba"};
I want to return only "bat" and "ball".
That's because they can be composed from two other elements in the array like so:
"bat" = "b" + "at"
"ball" = "ba" + "ll"
I have tried doing it with a foreach loop, but I'm not quite getting it right.
Any help will be much appreciated.
I have done something like
foreach(var x in list)
{
if (dataaccess.IsThreeCharacters(x))
{
for (int i = 0; i < arr.Length; i++)
{
for (int j = i; j < arr.Length; j++)
{
if(x == arr[i] + arr[j])
{
newlist.Add(x);
}
}
}
}
}
This will give you all of the values that can be composed from other values in the sequence:
var values = new HashSet<string>(new[] { "b", "at", "bat", "ct", "ll", "ball", "ba" });
var compositeValues =
from value in values
from otherValue in values
where value != otherValue
let compositeValue = value + otherValue
where values.Contains(compositeValue)
select compositeValue;
Notice the use of HashSet<string>, which gives O(1) lookup performance, as opposed to the O(N) of an array.
This should work although I'm not vouching for efficiency!
static void Main(string[] args)
{
var arr = new string[] { "b", "at", "bat", "ct", "ll", "ball", "ba" };
var composites = from s in arr
from lhs in arr
from rhs in arr
where s == string.Concat(lhs, rhs)
select s;
foreach (var composite in composites)
{
Console.WriteLine(composite);
}
Console.ReadLine();
}

Formatting a C# string with identical spacing in between values

I have 3 strings. The first set of strings are:
"1.0536"
"2.1"
"2"
The second is something like:
"Round"
"Square"
"Hex"
And the last are:
"6061-T6"
"T351"
"ASF.3.4.5"
I need to combine the three strings together with identical spacing in between each string. I can't use \t for tabbing as after I combine the strings, I send them to an Access Database.
When I combine the strings they look like:
"1.0536 Round 6061-T6"
"2.1 Square T351"
"2 Hex ASF.3.4.5"
I would really like them to look like this with the same exact amount of spacing in between each string:
"1.0536 Round 6061-T6"
"2.1 Square T351"
"2 Hex ASF.3.4.5"
How can I do this with C#?
You can use advanced features of string.Format:
string.Format("{0,-10}{1,-10}{2}", ...)
You can do the same thing by writing str.PadRight(10)
If you know the maximum lengths of each column then do the following:
String result = String.Format("{0} {1} {2}", strCol1.PadRight(10), strCol2.PadRight(9), strCol3.PadRight(9));
To make life easier, utility methods:
Usage
var data = new[] {
new[] { "ID", "NAME", "DESCRIPTION" },
new[] { "1", "Frank Foo", "lorem ipsum sic dolor" },
new[] { "2", "Brandon Bar", "amet forthrightly" },
new[] { "3", "B. Baz", "Yeehah!" }
};
var tabbedData = EvenColumns(20, data);
var tabbedData2 = string.Join("\n", EvenColumns(20, false, data)); // alternate line separator, alignment
Results
ID NAME DESCRIPTION
1 Frank Foo lorem ipsum sic dolor
2 Brandon Bar amet forthrightly
3 B. Baz Yeehah!
ID NAME DESCRIPTION
1 Frank Foolorem ipsum sic dolor
2 Brandon Bar amet forthrightly
3 B. Baz Yeehah!
Code
public string EvenColumns(int desiredWidth, IEnumerable<IEnumerable<string>> lists) {
return string.Join(Environment.NewLine, EvenColumns(desiredWidth, true, lists));
}
public IEnumerable<string> EvenColumns(int desiredWidth, bool rightOrLeft, IEnumerable<IEnumerable<string>> lists) {
return lists.Select(o => EvenColumns(desiredWidth, rightOrLeft, o.ToArray()));
}
public string EvenColumns(int desiredWidth, bool rightOrLeftAlignment, string[] list, bool fitToItems = false) {
// right alignment needs "-X" 'width' vs left alignment which is just "X" in the `string.Format` format string
int columnWidth = (rightOrLeftAlignment ? -1 : 1) *
// fit to actual items? this could screw up "evenness" if
// one column is longer than the others
// and you use this with multiple rows
(fitToItems
? Math.Max(desiredWidth, list.Select(o => o.Length).Max())
: desiredWidth
);
// make columns for all but the "last" (or first) one
string format = string.Concat(Enumerable.Range(rightOrLeftAlignment ? 0 : 1, list.Length-1).Select( i => string.Format("{{{0},{1}}}", i, columnWidth) ));
// then add the "last" one without Alignment
if(rightOrLeftAlignment) {
format += "{" + (list.Length-1) + "}";
}
else {
format = "{0}" + format;
}
return string.Format(format, list);
}
Specific to the Question
// for fun, assume multidimensional declaration rather than jagged
var data = new[,] {
{ "1.0536", "2.1", "2" },
{ "Round", "Square", "Hex" },
{ "6061-T6", "T351", "ASF.3.4.5" },
};
var tabbedData = EvenColumns(20, Transpose(ToJaggedArray(data)));
with Transpose:
public T[][] Transpose<T>(T[][] original) {
// flip dimensions
var h = original.Length;
var w = original[0].Length;
var result = new T[h][];
for (var r = 0; r < h; r++) {
result[r] = new T[w];
for (var c = 0; c < w; c++)
{
result[r][c] = original[c][r];
}
}
return result;
}
And multidimensional arrays (source):
public T[][] ToJaggedArray<T>(T[,] multiArray) {
// via https://stackoverflow.com/questions/3010219/jagged-arrays-multidimensional-arrays-conversion-in-asp-net
var h = multiArray.GetLength(0);
var w = multiArray.GetLength(1);
var result = new T[h][];
for (var r = 0; r < h; r++) {
result[r] = new T[w];
for (var c = 0; c < w; c++) {
result[r][c] = multiArray[r, c];
}
}
return result;
}
I know this has long since been answered, but there is a new way as of C# 6.0
string[] one = new string[] { "1.0536", "2.1", "2" };
string[] two = new string[] { "Round", "Square", "Hex" };
string[] three = new string[] { "1.0536 Round 6061-T6", "2.1 Square T351", "2 Hex ASF.3.4.5" };
for (int i = 0; i < 3; i++) Console.WriteLine($"{one[i],-10}{two[i],-10}{three[i],-10}");
The $"{one[i],-10}{two[i],-10}{three[i],-10}" is the new replacement for string.format . I have found it very useful in many of my projects. Here is a link to more information about string interpolation in c# 6.0:
https://learn.microsoft.com/en-us/dotnet/csharp/tutorials/string-interpolation
Use String.Format("{0,10}", myString)
Where 10 is the number of characters you want
To do it more dynamically you could do something like this: (hardcoding ahead!)
int padding = 3;
int maxCol0width = "Hello World!".Length;
int maxCol1width = "90.345".Length;
int maxCol2width = "value".Length;
string fmt0 = "{0,-" + (maxCol0width + padding) + "}";
string fmt1 = "{1,-" + (maxCol1width + padding) + "}";
string fmt2 = "{2,-" + (maxCol2width + padding) + "}";
string fmt = fmt0 + fmt1 + fmt2;
Console.WriteLine(fmt, "Hello World!", 90.345, "value");
Console.WriteLine(fmt, "Hi!", 1.2, "X");
Console.WriteLine(fmt, "Another", 100, "ZZZ");
You will of course need to figure out your max word widths by looping through each column's values. Also the creation of the format string could be significantly cleaned up and shortened.
Also note that you will need to use a non-proportional font for display, otherwise your columns will still not line up properly. Where are you displaying this data? There may be better ways of getting tabular output.

Help with Shannon–Fano coding

Hello I hope some one will help me with this=):
I have a set of some numbers, I need to divide them in two groups with approximately equal sum and assigning the first group with "1", second with "0", then divide each group the same way in to subgroups until subgroups will be one of number from set!
Picture explaining this crazy things):
pict
Here is the basic algorithm, if you know C# it's pretty simple to follow. And the program print the partitions as it explore the tree.
Note that there are some possible bugs and the code is light years away from the quality that a teacher would expect from an homework. (As i guess that it is an homework... if it's for work it's even worse my code would be pretty much Daily-WTF quality)
But it should allow you to understand the basic algorithm structure knowing that :
totalCount does the sum of the Count elements of the collection passed as parameter if you don't know Aggregate.
The other Aggregate usage is there for display, just ignore it.
I commented the sort as multiple elements have the same count and the C# sort function don't preserve order (And i wanted to get the same result as the wikipedia article)
The code:
var symbols = new[] {
new Symbol { Text = "A", Count=15, Probability=double.NaN, Code=""},
new Symbol { Text = "B", Count=7, Probability=double.NaN, Code="" },
new Symbol { Text = "C", Count=6, Probability=double.NaN, Code="" },
new Symbol { Text = "D", Count=6, Probability=double.NaN, Code="" },
new Symbol { Text = "E", Count=5, Probability=double.NaN, Code="" },
}.ToList();
Func<IEnumerable<Symbol>, int> totalCount =
symbols_ => symbols_.Aggregate(0, (a, s) => a + s.Count);
var total = totalCount(symbols);
foreach(var symbol in symbols)
{
symbol.Probability = total / symbol.Count;
}
//symbols.Sort((a, b) => b.Count.CompareTo(a.Count));
// Where is the Y-Combinator when you need it ?
Action<IEnumerable<Symbol>, string, int> recurse = null;
recurse = (symbols_, str, depth) => {
if (symbols_.Count() == 1)
{
symbols_.Single().Code = str;
return;
}
var bestDiff = int.MaxValue;
int i;
for(i = 1; i < symbols_.Count(); i++)
{
var firstPartCount = totalCount(symbols_.Take(i));
var secondPartCount = totalCount(symbols_.Skip(i));
var diff = Math.Abs(firstPartCount - secondPartCount);
if (diff < bestDiff) bestDiff = diff;
else break;
}
i = i - 1;
Console.WriteLine("{0}{1}|{2}", new String('\t', depth),
symbols_.Take(i).Aggregate("", (a, s) => a + s.Text + " "),
symbols_.Skip(i).Aggregate("", (a, s) => a + s.Text + " "));
recurse(symbols_.Take(i), str + "0", depth+1);
recurse(symbols_.Skip(i), str + "1", depth+1);
};
recurse(symbols, "", 0);
Console.WriteLine(new string('-', 78));
foreach (var symbol in symbols)
{
Console.WriteLine("{0}\t{1}\t{2}\t{3}", symbol.Code, symbol.Text,
symbol.Count, symbol.Probability);
}
Console.ReadLine();

Categories