I want to do a pattern match on the table below. If there is a match, take the values of the 2nd and 3rd column as answer. The first column can have 1 or multiple patterns, row 5 has only 1 pattern to match against.
local pattern_matrix = {
{{ "^small%-", "%-small%-", }, "small", 50},
{{ "^medium%-", "%-medium%-", }, "medium", 200},
{{ "^big%-", "%-big%-", }, "big", 3},
{{ "^large%-", "%-large%-", "^L%-", }, "large", 42},
{{ "%-special%-", }, "special", 5},
}
i am using the following code to find the row that matches the input:
local function determine_row(name)
for i = 1,#pattern_matrix,1 do
for _,pattern in pairs(pattern_matrix[i][1]) do --match against column 1
if name:match(pattern) then
return i --match found in row i
end
end
end
return 0
end
the result should be
determine_row("itsamedium") = 2
determine_row("blaspecialdiscount") = 5
determine_row("nodatatomatch") = 0
You're code looks mostly right but the pattern you're using is a bit off. You're not getting the expected index because all the patterns expect hyphens around the words being matched. (due to %- in your pattern)
As Allister mentioned, if you want to match the sample input from your question you can just add that literal word to your list of patterns. Judging from your usage, you may even be able to simplify the pattern. For case insensitive search, use lower() or upper() on your input before matching.
For example:
<script src="https://github.com/fengari-lua/fengari-web/releases/download/v0.1.4/fengari-web.js">
</script>
<script type='application/lua'>
local pattern_matrix =
{
{ "small", 50},
{ "medium", 200},
{ "big", 3},
{ "large", 42},
{ "special", 5},
}
local function determine_row(name)
for i, row in ipairs(pattern_matrix) do
if name:match(row[1]) then
return i -- match found in row i
end
end
return 0
end
local test_input = { "itsa-medium-", "itsBiG no hyphen", "bla-special-discount", "nodatatomatch" }
for _, each in ipairs(test_input) do
print( each, determine_row(each:lower()) )
end
</script>
Related
I have a weird problem that I can't solve since yesterday on Garry's Mod (GLua)
When my gmod server game is running, I notice that there are errors on arrays that are empty with certain keys when they are well specified, while doing deep tests, I noticed that the returned arrays were ... backwards.
Here is an array below:
bigArray = {
[ "default" ] = { 4, 2, 1 },
[ "police" ] = { 4, 2, 1 },
[ "mayor" ] = { 5, 2, 1 },
[ "sherif" ] = { 6, 2, 1 },
}
Good, next I will use the PrintTable() method (PrintTable() is a method already integrated in the game) which displays the contents of an array (This method, normally if I run PrintTable(bigArray) the result should be literally the array above, but here is the result displayed:
{
[ "sherif" ] = { 6, 2, 1 },
[ "mayor" ] = { 5, 2, 1 },
[ "police" ] = { 4, 2, 1 },
[ "default" ] = { 4, 2, 1 },
}
I will put an example more telling since the previous one is an dictionary and not really an array :
table = {
'truc',
'machin',
'chose'
}
If I display the first element of the table like this print(table[1]), the displayed result will be: chose
Flipping the tables upside down makes a lot of addons I use crash, I have no idea how this happened, it happened suddenly without me modifying any addon (I already looked at the worshop addons, none of them are responsible for the problem)
If someone has an idea how this could be caused, I'm interested, thanks.
Edit :
I installed my project on a virtual machine, and when I launched the server, I had none of the errors I mentioned.
I formatted my entire machine containing the errors and since then the problem is solved.
Following this observation, I still think that the problem did not come from the code, maybe my assembler or the game was corrupted, who knows.
Thanks for those who tried to answer my problem, and if someone one day encounters the same problem, I strongly advise him to check the integrity of their game.
I noticed that the returned arrays were ... backwards
They are not arrays. They are dictionaries (unordered set of key-value pairs).
An array in Lua would look like the following:
bigArray = {
{ name="default", 4, 2, 1 },
{ name="police", 4, 2, 1 },
{ name="mayor", 5, 2, 1 },
{ name="sherif", 6, 2, 1 },
}
In this case order of elements is preserved:
$ lua
Lua 5.4.4 Copyright (C) 1994-2022 Lua.org, PUC-Rio
> bigArray = {
{ name="default", 4, 2, 1 },
{ name="police", 4, 2, 1 },
{ name="mayor", 5, 2, 1 },
{ name="sherif", 6, 2, 1 },
}
> bigArray[1].name # This will _always_ be "default"
default
In Garry's Mod dictionaries are not stored in any particular order. If you want to iterate through a dictionary in order, rather than using pairs you must use either SortedPairs, SortedPairsByMemberValue or SortedPairsByValue.
See this wiki page for reference.
For your implementation, I would recommend adding a field to each member value of your bigArray dictionary to specify a sort order; for instance:
local bigArray = {
[ "default" ] = {
sortOrder = 1,
myValues = { 4, 2, 1 }
},
[ "police" ] = {
sortOrder = 2,
myValues = { 4, 2, 1 }
},
[ "mayor" ] = {
sortOrder = 3,
myValues = { 5, 2, 1 }
},
[ "sherif" ] = {
sortOrder = 4,
myValues = { 6, 2, 1 }
}
}
This would then allow you to iterate in order of the sortOrder value, like so:
for key, value in SortedPairsByMemberValue(bigArray, "sortOrder") do
print("\n" .. key .. ":")
PrintTable(value)
end
I'm currently trying to iterate over an array of hashes, and return all of the values of the "name" key in a string. Here's the array:
foods =
[
{ name: 'Dan Dan Noodles', cuisine: 'Sichuan', heat_level: 8 },
{ name: 'Nashville Hot Chicken', cuisine: 'American', heat_level: 7 },
{ name: 'Panang Curry', cuisine: 'Thai', heat_level: 4 },
]
Here's what I'm currently doing, and I'm not totally sure why it's not working!
foods.each do |food|
food.each do |k, v|
if food == :name
"#{v}"
end
end
end
Thanks in advance.
You can use Enumerable#map for this:
p foods.map { |f| f[:name] }
The code you tried to use did not produce any output or create any objects, and it was not necessary to use a second loop to access a single element of a hash.
I need to iterate over shoppingItem (items) inside shoppingOrder (orders). There are three orders. The first order has one item (itemid:1), second order has six items (itemid:2,3,4,5,6,7), third order has one item (itemid:8). I need to show only the top five items. i.e., 1,2,3,4,5 but the current code only limits the item in the second order, showing five items inside. The final output comes like 1,2,3,4,5,6,8
If first order has five items the loop should exit, if first order has one item and second order has six items, it has to show 1 in order 1 and 2,3,4,5 in order2 and exit before order3. But in my example, using order.shoppingItem.slice(0,5) only limits the items in the second order. It is not limiting the total items. How do I resolve this issue? I am using Vue JS version 2
NestedLoop.vue
<template>
<div>
<div v-for="order in shoppingOrder" :key="order.orderId">
<div v-for="item in order.shoppingItem.slice(0,5)" :key="item.itemId">
{{item.itemId}}
</div>
</div>
</div>
</template>
<script>
export default {
name: "NestedLoop",
data() {
return {
shoppingOrder: [
{
orderId: 1,
orderDate: "7/30/2020",
orderStatus: "Dispatched",
shoppingItem: [
{
itemId: 1,
itemName: "Pen",
itemQuantity: "1",
itemPrice: "10.00"
}
]
},
{
orderId: 2,
orderDate: "7/25/2020",
orderStatus: "Ordered",
shoppingItem: [
{
itemId: 2,
itemName: "Notebook",
itemQuantity: "2",
itemPrice: "40.00"
},
{
itemId: 3,
itemName: "Scale",
itemQuantity: "3",
itemPrice: "100.00"
},
{
itemId: 4,
itemName: "Sharpener",
itemQuantity: "1",
itemPrice: "10.00"
},
{
itemId: 5,
itemName: "DocumentFolder",
itemQuantity: "1",
itemPrice: "10.00"
},
{
itemId: 6,
itemName: "PencilBox",
itemQuantity: "5",
itemPrice: "140.00"
},
{
itemId: 7,
itemName: "SketchBox",
itemQuantity: "5",
itemPrice: "10.00"
}
]
},
{
orderId: 3,
orderDate: "7/34/2020",
orderStatus: "Dispatched",
shoppingItem: [
{
itemId: 8,
itemName: "Sketch",
itemQuantity: "1",
itemPrice: "10.00"
}
]
}
]
};
},
methods: {}
};
</script>
<style scoped>
</style>
Result
1
2
3
4
5
6
8
Expected only to return top 5 items like this (1 in order1 and then 2,3,4,5 in order2),
1
2
3
4
5
I love how succinct #Gaetan C's answer is, but .flat is a relatively new method that will require poly-filling for browsers if you are using Vue-cli 3. See this Github issue for more details. If you run into any challenges, you may need to manually edit the poly-fill option of the babel preset.
For more compatibility among other browsers or if you are using vue cli 2 or below, I present this solution.
computed: {
firstFiveShoppingItems: {
let initialShippingItem = [];
for (const order of this.shoppingOrder) {
if (initialShippingItem.length + order.shoppingItem.length >=5) {
return [...initialShippingItem, ...order.shoppingItem].slice(0, 5);
}
initialShippingItem = [...initialShippingItem, ...order.shoppingItem]
}
return initialShippingItem;
}
}
Then in your template, you add
<div v-for="item in firstFiveShoppingItems" :key="item.itemId">
{{item.itemId}}
</div>
As I said, it's not as elegant or succinct as #Gaetan C's answer but it will be more compatible among other browsers and you won't need to go through headaches with poly-fill configurations.
Another thing I like about my solution is that it doesn't iterate over all shopping item arrays like #Gaetan C's answer. It breaks when the result is obtained.
Just use a computed property instead to get the 5 first shopping items:
computed: {
firstShoppingItems: {
return this.shoppingOrder.map(x => x.shoppingItem).flat().slice(0, 5);
}
}
Then you just need one v-for loop:
<div v-for="item in firstShoppingItems" :key="item.itemId">
{{item.itemId}}
</div>
I'd recommend taking advantage of Vue's computed properties to make a list limited to five items. Currently your code is only slicing the inner list to five items.
computed: {
topFive() {
const limit = 5;
let count = 0;
let res = []
for (let i = 0; i < this.shoppingOrder.length && count < limit; i += 1) {
let order = this.shoppingOrder[i];
for (let j = 0; j < order.shoppingItem.length && count < limit; j += 1) {
let item = order.shoppingItem[j];
res.push(item);
count++;
}
}
return res;
}
Once you have a computed property, you can call it from the template like so:
<div v-for="item in topFive" :key="item.itemId">{{item.itemId}}</div>
Say my event looks like:
purchase = {
items: ["pickle", "turtle", "lexicon"]
}
How do I count how many events have "pickle"?
Use the equal operator.
var count = new Keen.Query("count", {
event_collection: "purchases",
timeframe: "this_14_days",
filters: [
{
property_name: "items",
operator: "eq",
property_value: "pickle"
}
]
});
From the API reference for filters & their operators:
“Equal to” – Note that if your property’s value is an array, “eq” can be used to filter for values inside that array. For example, eq: 5 will match a value of [5, 6, 7].
I am learning node and now I'm trying to order an array like this:
"lng" : [{
"ES" : 5,
"EN" : 3,
"IT" : 4
}]
(This is a part of a query result in MongoDB), I need to order the array by the number:
"ES" : 5,
"IT" : 4,
"EN" : 3
I used sort() but this function orders the array alphabetically by the first parameter, but I need order by the second, I've tried a lot of things but without result.
Thank you for your help!
JavaScript has no ordered objects, so first you should transform your object to an array of this kind:
[
{ key: "ES", value: 5 },
{ key: "EN", value: 3 },
{ key: "IT", value: 4 }
]
And then sort by the value key.
You can easily do it as follows:
// ("mongoDbResult" is the variable with an object you get from MongoDB)
var result = mongoDbResult.lng;
result = Object.keys(result).map(function (key) {
return { key: key, value: result[key] };
});
And then just sort by the value key:
result.sort(function (a, b) {
return (a.value < b.value) ? -1 : 1;
});
As a result, you should get a sorted array in the result variable.
Thank you Nikita, adding the key and value the sort works perfectly, my problem now is make the query to get the results with specific key and value...
I can get the elements by the KEY:
db.users.find({"lng.key" : "ES"})
Or by the VALUE:
db.users.find({"lng.value" : 5})
But not the both at the same query :/
[EDIT]
I have find the solution, $elemMatch:
db.users.find({lng_array : {$elemMatch:{key:"ES", value:5}}})