I want to create custom keyboard in telegram.bot
For example:
We have an array of string that gets from the database or other recurses
how we can push data from the array to InlineKeyboardMarkup in for loop or function
//array of Button
string[] ButtonItem= new string[] { "one", "two", "three", "Four" };
//function or solution to create keyboard like this
var keyboard = new InlineKeyboardMarkup(new[]
{
new[]
{
new InlineKeyboardButton("one"),
new InlineKeyboardButton("two"),
},
new[]
{
new InlineKeyboardButton("three"),
new InlineKeyboardButton("Four"),
}
});
You could use a separate function to get an array of InlineKeyboardButton
private static InlineKeyboardButton[][] GetInlineKeyboard(string [] stringArray)
{
var keyboardInline = new InlineKeyboardButton[1][];
var keyboardButtons = new InlineKeyboardButton[stringArray.Length];
for (var i = 0; i < stringArray.Length; i++)
{
keyboardButtons[i] = new InlineKeyboardButton
{
Text = stringArray[i],
CallbackData = "Some Callback Data",
};
}
keyboardInline[0] = keyboardButtons;
return keyboardInline;
}
And then call the function:
var buttonItem = new[] { "one", "two", "three", "Four" };
var keyboardMarkup = new InlineKeyboardMarkup(GetInlineKeyboard(buttonItem));
Create InlineKeyboardMarkup in a method:
public static InlineKeyboardMarkup InlineKeyboardMarkupMaker(Dictionary<int, string> items)
{
InlineKeyboardButton[][] ik = items.Select(item => new[]
{
new InlineKeyboardButton(item.Key, item.Value)
}).ToArray();
return new InlineKeyboardMarkup(ik);
}
Then use it like this:
var items=new Dictionary<int,string>()
{
{0 , "True" }
{1 , "False" }
};
var inlineKeyboardMarkup = InlineKeyboardMarkupMaker(items);
Bot.SendTextMessageAsync(message.Chat.Id, messageText, replyMarkup: inlineKeyboardMarkup);
Selecting True or False make an update with Update.CallbackQuery.Dataequal to selected item key (0 or 1).
Create InlineKeyboardButton with specific columns by below method.
public static IReplyMarkup CreateInlineKeyboardButton(Dictionary<string, string> buttonList, int columns)
{
int rows = (int)Math.Ceiling((double)buttonList.Count / (double)columns);
InlineKeyboardButton[][] buttons = new InlineKeyboardButton[rows][];
for (int i = 0; i < buttons.Length; i++)
{
buttons[i] = buttonList
.Skip(i * columns)
.Take(columns)
.Select(direction => new InlineKeyboardCallbackButton(
direction.Key, direction.Value
) as InlineKeyboardCallbackButton)
.ToArray();
}
return new InlineKeyboardMarkup(buttons);
}
Use method like this:
public static IReplyMarkup CreateInLineMainMenuMarkup()
{
Dictionary<string, string> buttonsList = new Dictionary<string, string>();
buttonsList.Add("one", "DATA1");
buttonsList.Add("two", "DATA2");
buttonsList.Add("three", "DATA3");
return CreateInlineKeyboardButton(buttonsList, 2);
}
Thanks pouladpld to create this function.
Related
There are two sets of:
int Transformer substations
object Buildings(the set is larger than the first set at least by 5 times).
The building has 2 parameters (number and load).
Need to create all possible combinations: each transformer station is loaded by 60-80% in every combination, and buildings don't repeat.
Glad to hear any suggestions.
Tried the Cartesian product but I have no idea how to apply it. Ideas just don't appear. I guess it is because of the stress produced by the war in Ukraine where I live.
A cartesian product without elements repetition in any given result set and without permutations:
static void combinations(List<List<string>> srs, int[] size, List<string> curr, int index)
{
if (index == srs.Count())
{
int s = curr.Count();
string[] d = new string[s];
List<string> x = d.ToList();
x.AddRange(curr);
x.RemoveAll(item => item == null);
dest.Add(x);
string res = "";
foreach (var item in x)
{
res += item + ", ";
}
//dest.add(d);
Console.WriteLine(res);
}
else
{
for (int i = 0; i < size[index]; i++)
{
int n = size[index];
string[] dim = new string[n];
dim = srs[index].ToArray();
curr.Add(dim[i]);
index++;
combinations(srs, size, curr, index);
index--;
curr.RemoveAt(curr.Count() - 1);
}
}
}
public static void init()
{
string[] confidence = new string[] { "High", "Low Variable" };
string[] goalspec = new string[] { "High", "Low Some" };
string[] quality = new string[] { "High", "Low Variable" };
string[] tansSkills = new string[] { "High", "Low some" };
string[] sitLead = new string[] { "S1", "S2", "S3", "S4" };
string[] devLev = new string[] { "D1", "D2", "D3", "D4" };
string[] statReason = new string[] {"In backlog", "Canceled", "Completed" };
List<List<string>> srs = new List<List<string>>
{
confidence.ToList(),
goalspec.ToList(),
quality.ToList(),
tansSkills.ToList(),
sitLead.ToList(),
devLev.ToList(),
statReason.ToList()
};
number_elem = srs.Count();
int[] size = new int[number_elem];
size[0] = confidence.Count();
size[1] = goalspec.Count();
size[2] = quality.Count();
size[3] = tansSkills.Count();
size[4] = sitLead.Count();
size[5] = devLev.Count();
size[6] = statReason.Count();
dest = new List<List<string>>();
List<string> curr = new List<string>();
combinations(srs, size, curr, 0);
}
With a sorted list:
[11] = "a"
[22] = "b"
[35] = "c"
[40] = "d"
[45] = "e"
and a list of keys:
[35, 40, 45]
how can I get the data matching the list of keys.
the output should be:
["c", "d", "e"]
Edit:
The type is SortedList()
the class 'SomeClass' contains the key value as well.
an example would be:
class SomeClass
{
string Key;
... some other fields
}
my attempt was:
MyList.Values.Where(_ => keys.Contains(_.key)).ToList();
but this is not using the index.
This works as long as all elements can be found:
public class A
{
public string Key;
public string SomeValue;
}
var l = new SortedList<string, A>
{
["aa"] = new A { Key = "aa" },
["bb"] = new A { Key = "bb" },
["cc"] = new A { Key = "cc" },
["dd"] = new A { Key = "dd" }
};
var ids = new List<string> { "bb", "cc" };
var r = ids.Select(i => l[i]).ToList();
Following the advice of using TryGetValue is good, but I'm not sure how to combine it with select.
Depending on the size of the SortedList and the size of ids, the below code maybe worth considering (to avoid iterating over the entirety of SortedList). It will be particularly beneficial if ids is small and list is large.
using System;
using System.Linq;
using System.Collections.Generic;
namespace ConsoleApp12
{
public class Program
{
public static void Main(string[] args)
{
var list = new SortedList<string, SomeClass>
{
["aa"] = new SomeClass { Key = "aa" },
["bb"] = new SomeClass { Key = "bb" },
["cc"] = new SomeClass { Key = "cc" },
["dd"] = new SomeClass { Key = "dd" }
};
var ids = new List<string> { "bb", "cc" };
var results = ids.Select(x =>
{
list.TryGetValue(x, out var matching);
return matching;
}).Where(z => z != null);
// Output to show the results
Console.WriteLine(string.Join(",", results.Select(z => z.Key)));
}
}
}
So, this will work?
var list = new SortedList<string, SomeClass>
{
["aa"] = new SomeClass { Key = "aa" },
["bb"] = new SomeClass { Key = "bb" },
["cc"] = new SomeClass { Key = "cc" },
["dd"] = new SomeClass { Key = "dd" }
};
var ids = new List<string> { "bb", "cc" };
var results = list.Where(x => ids.Contains(x.Key)).ToList();
If you need only the SomeClass list:
var someClassList = list.Where(x => ids.Contains(x.Key)).Select(y => y.Value);
Say I have a data class like this and a list of its objects:
public class DataSet
{
public int A { get; set; }
public string B { get; set; }
public double C { get; set; }
}
var data = new List<DataSet>
{
new DataSet() { A = 1, B = "One", C = 1.1 },
new DataSet() { A = 2, B = "Two", C = 2.2 },
new DataSet() { A = 3, B = "Three", C = 3.3 }
};
I would like to do a Select() on the list, based on different properties. For example, if I need a list of property A, I could do this easily:
var listA = data.Select(x => x.A).ToList();
All good so far.
But in my program, I need to do the above, only, I wouldn't know whether I need a list of A or B or C until runtime. This 'knowledge' of what to select is stored in a list of strings, and I need to iterate it and extract only the appropriate lists. Something like this:
// GetKeys() will return the keys that I need to extract.
// So at one time keyList could have "A" and "B", another time "B" and "C" etc.
List<string> keyList = GetKeys();
foreach (var key in keyList)
{
// What do I do here?
data.Select(x =>???).ToList();
}
Is this possible at all? I'm fine with even a non-LINQ solution, if it achieves my goal.
EDIT:
Clarifying the requirement.
The end result I want is a separate list based on each 'key' mentioned above. So, something like
List<List<object>>
The count in outer list would be the count of keyList.
The inner list would have as many items as in DataSet.
This would probably not be the most efficient solution, but you could use Reflection for a fully dynamic solution:
private static List<List<object>> SelectDynamicData<T>(IEnumerable<T> data, List<string> properties)
{
// get the properties only once per call
// this isn't fast
var wantedProperties = typeof(T)
.GetProperties()
.Where(x => properties.Contains(x.Name))
.ToArray();
var result = new Dictionary<string, List<object>>();
foreach (var item in data)
{
foreach (var wantedProperty in wantedProperties)
{
if (!result.ContainsKey(wantedProperty.Name))
{
result.Add(wantedProperty.Name, new List<object>());
}
result[wantedProperty.Name].Add(wantedProperty.GetValue(item));
}
}
return result.Select(x => x.Value).ToList();
}
And, of course, you'd need to do a double foreach or a LINQ query to print that. For example:
var data = new List<DataSet>
{
new DataSet() { A = 1, B = "One", C = 1.1 },
new DataSet() { A = 2, B = "Two", C = 2.2 },
new DataSet() { A = 3, B = "Three", C = 3.3 }
};
var selectedData = SelectDynamicData(data, new List<string> { "A", "C" });
foreach (var list in selectedData)
{
foreach (object item in list)
{
Console.Write(item + ", ");
}
Console.WriteLine();
}
Using Creating Expression Trees by Using the API you can build an expression tree to represent the linq query you were hard coding in order to make it more dynamic.
Expression<Func<TModel, object>> GetPropertyExpression<TModel>(string propertyName) {
// Manually build the expression tree for
// the lambda expression v => v.PropertyName.
// (TModel v) =>
var parameter = Expression.Parameter(typeof(TModel), "v");
// (TModel v) => v.PropertyName
var property = Expression.Property(parameter, propertyName);
// (TModel v) => (object) v.PropertyName
var cast = Expression.Convert(property, typeof(object));
var expression = Expression.Lambda<Func<TModel, object>>(cast, parameter);
return expression;
}
Review the comments to understand the building of the expression tree.
This now can be used with the data to extract the desired result.
Following similar to what was provided in another answer it would be simplified to
List<List<object>> SelectDynamicData<T>(IEnumerable<T> data, List<string> properties) {
return properties
.Select(_ => data.Select(GetPropertyExpression<T>(_).Compile()).ToList())
.ToList();
}
Both methods are displayed in the following example
[TestMethod]
public void TestMethod1() {
var data = new List<DataSet>
{
new DataSet() { A = 1, B = "One", C = 1.1 },
new DataSet() { A = 2, B = "Two", C = 2.2 },
new DataSet() { A = 3, B = "Three", C = 3.3 }
};
var propertyKnownAtRuntime = "A";
var expression = GetPropertyExpression<DataSet>(propertyKnownAtRuntime);
var listA = data.Select(expression.Compile()).ToList();
//Produces
// { 1, 2, 3}
var listAC = SelectDynamicData(data, new List<string> { "A", "C" });
//Produces
//{
// { 1, 2, 3},
// { 1.1, 2.2, 3.3 }
//}
}
You can use reflection, for example
string key = "A";
var query = data.Select(x =>
{
var prop = x.GetType().GetProperty(key); //NOTE: if key does not exist this will return null
return prop.GetValue(x);
});
foreach (var value in query)
{
Console.WriteLine(value); //will print 1, 2, 3
}
Below is the code where key is being hard-coded in Dictionary
var datalist = new List<IDictionary<string, string>>();
for (var i = 0; i < dt.Rows.Count; ++i)
{
var data = new Dictionary<string, string>()
{
{ "ID", Convert.ToString(dt.Rows[i]["ID"]) },
{ "STATUS", Convert.ToString(dt.Rows[i]["Name"]) },
{ "TYPE", Convert.ToString(dt.Rows[i]["TYPE"]) }
};
datalist.Add(data);
}
Now, instead of hard-coding the keys like ID, STATUS, etc, I want to add it from my string array containing the values below
string[] arrNames = ConfigurationManager.AppSettings["NameKey"].Split(',');
How can I traverse arrNamesto add keys in Dictionary and then add in List?
Iterate through the collection of names:
var datalist = new List<IDictionary<string, string>>();
string[] arrNames = ConfigurationManager.AppSettings["NameKey"].Split(',');
for (var i = 0; i < dt.Rows.Count; ++i)
{
var data = new Dictionary<string, string>();
foreach (var name in arrNames)
{
data[name] = Convert.ToString(dt.Rows[i][name]);
}
datalist.Add(data);
}
your code should look something like this
var datalist = new List<IDictionary<string, string>>();
string[] arrNames = Convert.ToString(ConfigurationManager.AppSettings["NameKey"]).Split(',');
if (arrNames.Length == 3)
{
for (var i = 0; i < dt.Rows.Count; ++i)
{
var data = new Dictionary<string, string>()
{
{ arrNames[0], Convert.ToString(dt.Rows[i][arrNames[0]]) },
{ arrNames[1], Convert.ToString(dt.Rows[i][arrNames[1]]) },
{ arrNames[2], Convert.ToString(dt.Rows[i][arrNames[2]]) }
};
datalist.Add(data);
}
}
You can use linq method ToDictionary. Try this code:
string[] arrNames = // new[] {"ID", "STATUS", "TYPE"};
var datalist = new List<IDictionary<string, string>>();
for (var i = 0; i < dt.Rows.Count; ++i)
datalist.Add(
arrNames
.Select(key =>
new
{
key,
value = Convert.ToString(dt.Rows[i][key])
}
)
.ToDictionary(x => x.key, x => x.value)
);
If you prefer LINQ-y and concise you could try something like:
var names = ConfigurationManager.AppSettings["NameKey"].Split(',');
var list = dt.AsEnumerable()
.Select(r => names.ToDictionary(n => n, n => r[n]))
.ToList();
Here I'm assuming dt is a DataTable.
If you have at least the same number of items in your arrNames array than columns you want to read and of course with this order, then you can hardcore the indexes.
var datalist = new List<IDictionary<string, string>>();
for (var i = 0; i < dt.Rows.Count; ++i)
{
var data = new Dictionary<string, string>()
{
{ arrNames[0], Convert.ToString(dt.Rows[i]["ID"]) },
{ arrNames[1], Convert.ToString(dt.Rows[i]["Name"]) },
{ arrNames[2], Convert.ToString(dt.Rows[i]["TYPE"]) }
};
datalist.Add(data);
}
EDIT: I am completely redoing my questions as I have figured out the simplest way of asking it. Thanks to the commenters so far that got me thinking about the root problem.
public List<string> GetAllPossibleCombos(List<List<string>> strings)
{
List<string> PossibleCombos = new List<string>();
//????
{
string combo = string.Empty;
// ????
{
combo += ????
}
PossibleCombos.Add(combo);
}
return PossibleCombos;
}
I need to figure out how to recursively go through each List<string> and combine 1 string from each list into a combo string. Don't worry too much about formatting the string as the "live" code uses a custom object instead. Also, feel free to assume that every list will contain at least 1 string and that there are no null values.
Here is a simple non-recursive solution that just concatenates the elements of each combination:
public static List<string> GetAllPossibleCombos(List<List<string>> strings)
{
IEnumerable<string> combos = new [] { "" };
foreach (var inner in strings)
combos = from c in combos
from i in inner
select c + i;
return combos.ToList();
}
static void Main(string[] args)
{
var x = GetAllPossibleCombos(
new List<List<string>>{
new List<string> { "a", "b", "c" },
new List<string> { "x", "y" },
new List<string> { "1", "2", "3", "4" }});
}
You could generalize this to return an IEnumerable<IEnumerable<string>>, which allows the caller to apply any operation they like for transforming each combination into a string (such as the string.Join below). The combinations are enumerated using deferred execution.
public static IEnumerable<IEnumerable<string>> GetAllPossibleCombos(
IEnumerable<IEnumerable<string>> strings)
{
IEnumerable<IEnumerable<string>> combos = new string[][] { new string[0] };
foreach (var inner in strings)
combos = from c in combos
from i in inner
select c.Append(i);
return combos;
}
public static IEnumerable<TSource> Append<TSource>(
this IEnumerable<TSource> source, TSource item)
{
foreach (TSource element in source)
yield return element;
yield return item;
}
static void Main(string[] args)
{
var combos = GetAllPossibleCombos(
new List<List<string>>{
new List<string> { "a", "b", "c" },
new List<string> { "x", "y" },
new List<string> { "1", "2", "3", "4" }});
var result = combos.Select(c => string.Join(",", c)).ToList();
}
Hope this helps.
class NListBuilder
{
Dictionary<int, List<string>> tags = new Dictionary<int, List<string>>();
public NListBuilder()
{
tags.Add(1, new List<string>() { "A", "B", "C" });
tags.Add(2, new List<string>() { "+", "-", "*" });
tags.Add(3, new List<string>() { "1", "2", "3" });
}
public List<string> AllCombos
{
get
{
return GetCombos(tags);
}
}
List<string> GetCombos(IEnumerable<KeyValuePair<int, List<string>>> remainingTags)
{
if (remainingTags.Count() == 1)
{
return remainingTags.First().Value;
}
else
{
var current = remainingTags.First();
List<string> outputs = new List<string>();
List<string> combos = GetCombos(remainingTags.Where(tag => tag.Key != current.Key));
foreach (var tagPart in current.Value)
{
foreach (var combo in combos)
{
outputs.Add(tagPart + combo);
}
}
return outputs;
}
}
}
In case it helps anyone, here is the method syntax version for Douglas's GetAllPossibleCombos method.
public static List<string> GetAllPossibleCombos(List<List<string>> strings)
{
IEnumerable<string> combos = new[] { "" };
foreach (var inner in strings)
{
combos = combos.SelectMany(r => inner.Select(x => r + x));
}
return combos.ToList();
}
Here is a generic version that works with all object types:
public static List<List<T>> GetAllPossibleCombos<T>(List<List<T>> objects)
{
IEnumerable<List<T>> combos = new List<List<T>>() { new List<T>() };
foreach (var inner in objects)
{
combos = combos.SelectMany(r => inner
.Select(x => {
var n = r.DeepClone();
if (x != null)
{
n.Add(x);
}
return n;
}).ToList());
}
// Remove combinations were all items are empty
return combos.Where(c => c.Count > 0).ToList();
}
If you provide null values it will also give you empty combination. For example:
var list1 = new List<string>() { "1A", "1B", null };
var list2 = new List<string>() { "2A", "2B", null };
var output = GetAllPossibleCombos(allLists);
Will contain:
[["1A"], ["1B"], ["2A"], ["2B"], ["1A", "2A"], ["1A", "2B"], ["1B", "2A"], ["1B," "2B"]]
Rather than just:
var list1 = new List<string>() { "1A", "1B" };
var list2 = new List<string>() { "2A", "2B" };
var output = GetAllPossibleCombos(allLists);
[["1A", "2A"], ["1A", "2B"], ["1B", "2A"], ["1B," "2B"]]
Note: DeepClone is an extension method used for copying the list. This can be done in many ways
public static T DeepClone<T>(this T source)
{
// Don't serialize a null object, simply return the default for that object
if (Object.ReferenceEquals(source, null))
{
return default(T);
}
var deserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace };
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), deserializeSettings);
}
Here is an answer that would work for any generic type, comes with a function to convert base-10 to base-n as well.
public static class IntExt
{
const string Symbols = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
public static string ToString(this int value, int toBase)
{
switch (toBase)
{
case 2:
case 8:
case 10:
case 16:
return Convert.ToString(value, toBase);
case 64:
return Convert.ToBase64String(BitConverter.GetBytes(value));
default:
if (toBase < 2 || toBase > Symbols.Length)
throw new ArgumentOutOfRangeException(nameof(toBase));
if (value < 0)
throw new ArgumentOutOfRangeException(nameof(value));
int resultLength = 1 + (int)Math.Max(Math.Log(value, toBase), 0);
char[] results = new char[resultLength];
int num = value;
int index = resultLength - 1;
do
{
results[index--] = Symbols[num % toBase];
num /= toBase;
}
while (num != 0);
return new string(results);
}
}
}
public class UnitTest1
{
public static T[][] GetJoinCombinations<T>(T[][] arrs)
{
int maxLength = 0;
int total = 1;
for (int i = 0; i < arrs.Length; i++)
{
T[] arr = arrs[i];
maxLength = Math.Max(maxLength, arr.Length);
total *= arr.Length;
}
T[][] results = new T[total][];
int n = 0;
int count = (int)Math.Pow(maxLength, arrs.Length);
for (int i = 0; i < count; i++)
{
T[] combo = new T[arrs.Length];
string indices = i.ToString(maxLength).PadLeft(arrs.Length, '0');
bool skip = false;
for (int j = 0; j < indices.Length; j++)
{
T[] arr = arrs[j];
int index = int.Parse(indices[j].ToString());
if (index >= arr.Length)
{
skip = true;
break;
}
combo[j] = arr[index];
}
if (!skip)
results[n++] = combo;
}
return results;
}
[Fact]
public void Test1()
{
string[][] results = GetJoinCombinations(new string[][]
{
new string[] { "1", "2", "3" },
new string[] { "A", "B", "C" },
new string[] { "+", "-", "*", "/" },
});
}
}
public static IEnumerable<int[]> GetAllPossibleCombos(List<int[]> ints)
=> _getAllPossibleCombos(ints, 0, new List<int>());
private static IEnumerable<int[]> _getAllPossibleCombos(IReadOnlyList<int[]> ints, int index, IReadOnlyCollection<int> current)
{
return index == ints.Count - 1
? ints[index]
.Select(_ => new List<int>(current) {_}.ToArray())
: ints[index]
.SelectMany(_ => _getAllPossibleCombos(ints, index + 1, new List<int>(current) {_}));
}