I am automating some website and I got stuck on such a case. I have a list created, everything is great for me, it has 24 elements. These are products from the store, containing their picture, name, price, etc. But now I need to take two things from the first element and display in the console, namely name and price. Is anyone able to suggest something? I sit and thinks but nothing comes out. All I managed to do was send everything for 1 item.
I tried resolve that with some Linq but without success.
public List<string> ListOfElements()
{
var elements = new List<string>();
IReadOnlyCollection<IWebElement> listElements = _driver.FindElements(By.CssSelector(".category-list div[class='cat-prod-row js_category-list-item js_clickHashData js_man-track-event ']");
foreach (IWebElement element in listElements)
{
elements.Add(element.Text);
}
return elements;
}
public void DisplayFirstElement()
{
var firstElement = ListOfElements();
Console.WriteLine(firstElement[0]);
}
I want get name and price of first element and then assert that price for that is greater than 10.
You´re flattening all the elements properties into a single collection of strings. Thus you´re losing any relationship between those strings. It´s hard to say what the 22rd element within thhat list actually is: is it a price? A name? Something completey different? To which item does it actually belong?
Instead you should just return a list of entities and then print the properties of the very first entitity:
public List<IWebElement> ListOfElements()
{
var elements = new List<string>();
return listElements = _driver.FindElements(By.CssSelector(".category-list div[class='cat-prod-row js_category-list-item js_clickHashData js_man-track-event ']");
}
public void DisplayFirstElement()
{
var allElements = ListOfElements();
var firstElement = allElements.First();
Console.WriteLine("FirstName: " + firstElement.Name + " Price: " + firstElement.Price);
}
Of course this assumes your IWebElement has a Name- and a Price-property.
Related
I have to print all the text of the web elements, so i am storing the web elements in list "test" and then getting text of each web element and keep them adding to other list "Title".
Now when i am trying to print all the elements of list "Title".But only the text of 1st element is printed.
Please help me to find where i am going wrong.
public void PrintText()
{
var Title = new List<string>();
IList <IWebElement> test=Controls.GetWebElementList(X-path);
foreach (var g in test)
{
Title.Add(Controls.GetText(x-path));
}
foreach (var h in Title)
{
Console.WriteLine(h);
}
}
It's not that clear how Controls.GetWebElementList() is defined.
Ideally to extract the texts you have to induce WebDriverWait for VisibilityOfAllElementsLocatedBy() and you can use the following Locator Strategy:
IList <IWebElement> test = new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.VisibilityOfAllElementsLocatedBy(By.XPath("X-path")));
Your code looks fine.
Try to verify the first list to print their values.
And then run again, maybe your first line had only one value.
I have a dropdown with three strings horizontally for each item. How can I alphabetically sort first by string 1 from each item, then by string 2 from each item?
Here's my snippet:
foreach (var item in list)
{
if(typeof(T).Equals(typeof(Machine)))
{
Machine machine = (item as Machine);
string title = machine.MachineName + " - " + machine.Serial + " - " + machine.MachineOwnership;
alert.AddAction(UIAlertAction.Create(title, UIAlertActionStyle.Default, action => {
button.SetTitle(title, UIControlState.Normal);
}));
}
else if(typeof(T).Equals(typeof(Person)))
{
alert.AddAction(UIAlertAction.Create((item as Person).Name, UIAlertActionStyle.Default, action => {
button.SetTitle((item as Person).Name, UIControlState.Normal);
}));
}
}
Where list contains objects of type Machine which has the following properties:
MachineName, Serial and MachineOwnshership (all strings).
So I want to do something like OrderBy(MachineName).ThenBy(Serial) but not sure how to do so correctly when I'm first checking to see what the list type is and then populating the dropdown list per item.
My dropdown list looks something like this if anyone needs clarification:
-------------------------------------------------
MachineNameStartsWithA - 01234 - OwnerStartsWithA
--------------------------------------------------
MachineNameStartsWithB - 012345 - OwnerStartsWithB
---------------------------------------------------
etc.... where it's a long list of items where the strings are separated by "-" like it's shown in the code.
Also, for what it's worth, this is currently inside a Xamarin app.
I think something like this should work. Sorting by a Tuple should be lexicographic:
list.OfType<Machine>().OrderBy(x => new Tuple<string,string>(x.MachineName,x.Serial))
The OfType call should also remove the need for the typeof check and cast - the result should be an iterable of Machines.
Per the comment regarding multiple object types:
Grouping like types together
This would be my default preference from a UI/UX perspective unless it really makes sense to mix Machines and Persons together. Depending on the length of the list it may be preferable to split on the element type first as list.OfType will enumerate the entire list each time.
foreach(var item in list.OfType<Machine>().OrderBy(x => new Tuple<string,string>(x.MachineName,x.Serial)))
{
// append item
}
foreach(var item in list.OfType<Person>().OrderBy(x => x.Name))
{
// append item
}
Interleaving various types
private Tuple<string,string> Projection(BaseClass x)
{
Machine item = x as Machine;
if(item != null)
{
return new Tuple<string,string>(item.MachineName,item.Serial);
}
Person item = x as Person;
if(item != null)
{
return new Tuple<string,string>(item.Name,"");
}
}
foreach(var item in list.OrderBy(Projection))
{
// check type of item and append as appropriate
}
I have code to create a grouped list for a ListView in Xamarin Forms, which for some reason only sometimes removes a group from the list if it is empty.
char[] alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
var animals = new List<string>() { "Jaguar", "Elephant", "Nemo", "Cat", "Dog", "Iguana", "Puma", "Crow", "Hawk", "Owl", "Badger", "Meerkat", "Lion", "Tiger", "Rabbit", "Pig" };
var groups = new ObservableCollection<GroupedItemModel>();
for (int i = 0; i < alpha.Length; i++)
{
groups.Add(new GroupedItemModel(alpha[i].ToString()));
}
foreach (var _group in groups)
{
foreach (var _animal in animals)
{
if (_animal[0].ToString().ToUpper() == _group.GroupName.ToUpper())
{
_group.Add(_animal);
}
}
}
for (int i = 0; i < groups.Count; i++)
{
if (groups[i].Count == 0)
{
groups.RemoveAt(i);
}
}
ListSource = groups;
However, this happens:
Why do these groups not get removed? Any solutions?
When removing from a list you need to work backwards.
such as:
if you have 1,2,3,4,5,6,7,8,9,10 and you say remove even numbers as its 1-10,
on 1 thats ok, on 2, you remove it, so 3 moves into its place.. so now you arent checking 3...you skip to 4.. so in this example you'd get away withit, but what if your list was already missing say 3, it would have moved number 4 to the place where 2 had been, and move on, 4 would be missed
Change your for loop to be decremental
As described by BugFinder above, the problem you are getting is caused by modifying the list as you iterate through it. Problem solved. But it might also be worth taking a look at the overall approach. Currently we:
Create list of all possible groups (A-Z)
Iterate though the list of animals and add each to a group based upon the first letter
Iterate though the groups and throw away any which are empty.
This can all be done with a few lines of Linq code and a tweak to the GroupedItemModel
public class GroupedItemModel
{
public GroupedItemModel(string name, IEnumerable<string> values){
Name = name;
Values = new List<string>(values);
}
public string Name { get; }
public List<string> Values { get; }
}
We can now populate an ObservableCollection<GroupedItem> with
new ObservableCollection<GroupedItem>(animals.GroupBy(a => char.ToUpper(a[0]).ToString()).OrderBy(g => g.Key).Select(g => new GroupedItem(g.Key, g)));
Very minor afterword: Prefixing variable names with underscores is usually used for member variables of a class, not for local variables (_group, _animal). It doesn't change how the code works but when sharing code with others, using the general conventions helps speed up reading and understanding the code.
I am unsure how take data from an IEnum object and dump it to a Dictionary and/or List, and would appreciate any guidance.
I'm working on a program that sorts through a collection of data pulled from SQL DB. I'm using Enterprise Library 5 (Data Access Application Block). So far there is an adapter class that will create an instance of the DB, map the query results to appropriate fields (Namely: First, middle, last names, DoB, and an ID), and it has two methods of type IEnumerable that will pass the SQL statement. I am unsure of how the the return IEnum object looks like. One method will return a list of offenders and another will return a list of all the records based on DoB:
public IEnumerable<Person> GetOffenders()
{
var people =
_db.ExecuteSqlStringAccessor<Person>(#"SELECT pm.Local_ID, pm.First_Name, pm.Last_Name, pm.Middle_Name, pm.DOB
FROM Person_Main pm ", _personRowMapper);
return people;
}
In another class that will hold the matching logic, I am trying to "dump" the contents of the getOffenders() which was defined in the adapter class, the idea is iterate over the two lists (offenders and all records based on DoB). I'm assuming the a good route would be to use a Dictionary to hold the results from getOffenders(). So far I've got this test code, which only checks to see if the connection to the DB is successful and retrieves a row of dummy data I entered:
PersonAdapter personAdapter = new PersonAdapter();
private Dictionary<String, List<Person>> testDictionary = new Dictionary<String, List<Person>>();
public void Test1()
{
var offenders = personAdapter.GetOffenders();
var pList = new List<Person>();
// Test to see if GetOffenders is returning data correctly
foreach (var variable in offenders)
{
var fName = variable.FirstName;
var mName = variable.MiddleName;
var lName = variable.LastName;
var lId = variable.LocalId;
Console.WriteLine(variable.FirstName + " " + variable.MiddleName + " " +
variable.LastName + " " + variable.LocalId);
Console.ReadLine();
}
An IEnumerable implementation only returns one item at a time. If you want to transfer those to a static collection you will need to loop through the IEnumerable collection and then do a List<Person>.Add(item).
foreach(var item in offenders)
{
pList.Add(item);
}
Then you can use your pList collection as a normal List<> to then add to your testDictionary field.
testDictionary.Add("some_string_key", pList);
I've looked into various different ways of array's, arraylist's, dictionaries... but as I'm used to PHP I'm not entirely sure on the best way I could collect the following information.
My program loops through each user, and if their is a location ID, I want to add that to some sort of collection / array. It's expected that different users will have the same location ID.
If the location ID is the same, I need to increase an integer of how many occurrence for that location ID.
Example:
User1 - Location1
User2 - Location3
User3 - Location3
Location1 = 1
Location3 = 2
Also I need to somehow append each user ID to this collection. So Location3 / 2 occurrences / user2/user3
I've been trying to figure out the best way of doing this for about two hours now, and all the different methods of multidimensional arrays, arraylists, dictionaries is all a little confusing as it all seems abstract to my PHP knowledge. I think C# handles arrays in an entirely different way.
Essentially, the collection with unique location ID's / occurrences / and users collection needs to be stored in something that can be passed to somewhere else in my program as an argument.
I've made a PHP script which does exactly what I'm after
foreach($call["data"] as $v)
{
// Foreach USER ($v containing their unique ID and location ID.)
$user_id = $v["id"];
$location_id = $v["location"]["id"];
// This adds the location ID as the key within the array, followed by every user who has it. I don't need a count in this case, as I could just count the number of users.
$collection[$location_id][$user_id] = null;
}
This in return creates this array when printed using print_r
[106078429431815] => Array
(
[620790873] =>
[626276302] =>
[100000152470577] =>
)
(Small part of the output). - Added PHP Example.
Anyone know how I can get C# to collect the same information in the same way my PHP array does?
using System.Linq;
var grouppingByLocation = users.GroupBy(u => u.LocationID);
foreach (var g in grouppingByLocation)
{
Console.WriteLine("Location id: {0}", g.Key);
foreach (var u in g)
{
Console.WriteLine("User id: {0}", u.ID);
}
}
See Enumerable.GroupBy() for more details.
This is an Extension Method over IEnumerable<T> interface implemented by any built-in collection (such as Array T[], List<T>, Dictionary<K,V>, etc.) which accepts a lambda expression pointing to a property of class collection of which you're grouping by.
If you want to build the list looping through initial data, you can create object like this:
var list = new Dictionary<int, Tuple<int, List<int>>();
And fill it in the loop
if(list[locationID]==null) list[locationID] = Tuple.Create(0,new List<int>());
//..
list[locationId].Item1++; // counter
list[locationId].Item2.Add(userId); //list of users
Create an object to hold each item of data.
public Class Model{
public int LocationId {get;set;}
public int Occurences{get;set;}
public IList<User> Users{get;set;}
}
Initialize the container as a list of items.
var container = List<Model>();
Process you list of users.
foreach(var user in userList){
var model = container.SingleOrDefault(x=> x.LocationId == user.LocationId);
if(model != null){
model.Users.Add(user);
} else{
model = new Model{
model.Users = new List<User>.Add(user);
model.LocationId = user.LocationId;
container.Add(model)
}
model.Occruences ++;
}
}
var byLocation = users.Where(u => !string.IsNullOrEmpty(u.Location))
.GroupBy(u => u.Location);
var stats = byLocation.Select(l => string.Format("{0} / {1} occurrences / {2}",
l.Key, l.Count(), string.Join("/", l.Select(u => u.User)));
// And just to print the result
foreach (var location in stats)
Console.WriteLine(location);