issue creating a list with basic python loop for a in b: - maya

I am trying to create a list in python that is filled with the elements I have selected in Autodesk Maya. However, when I select more than one element, this element gets duplicated. I thing this is a really simple issue because I'm not looping correctly and then an key gets added to my list more than once.
If someone with more knowledge could take a look and give me some advice would be great!
Many thanks in advance,
Joan
items = []
selectedObjects = cmds.ls(sl=True)
strItems = []
for item in selectedObjects:
b = item.encode('utf-8')
strItems.append(b)
for item1 in strItems:
lenItem = len(item1)
lenItemNoGrp = lenItem - 5
lenItemNoGrp2 = lenItem - 6
grp = item1[lenItemNoGrp:lenItem]
grp2 = item1[0:lenItemNoGrp2]
grpName = grp2
if grp == 'group':
items.append({
"type": "maya_file",
"name": shotName + 'V' + versionStr + grpName,
})
else:
None

You are looping over the complete content of strItem every time you add something to it. Let's say you have selected obj1 and obj2. Then
obj1 is added to the list
the second loop takes obj1 and does something with it
the outer loop stars again and adds obj2 to the list
the inner loop again takes all contents of the list and first takes obj1 and then obj2
So iterating over the canging list is maybe not what you want to do in this case.

It looks like you indented the loop by accident. This version is still missing the variables shotName and versionString but it will not duplicate things
items = []
selectedObjects = cmds.ls(sl=True)
strItems = []
for item in selectedObjects:
b = item.encode('utf-8')
strItems.append(b)
for item1 in strItems:
lenItem = len(item1)
lenItemNoGrp = lenItem - 5
lenItemNoGrp2 = lenItem - 6
grp = item1[lenItemNoGrp:lenItem]
grp2 = item1[0:lenItemNoGrp2]
grpName = grp2
if grp == 'group':
items.append({
"type": "maya_file",
"name": shotName + 'V' + versionStr + grpName,
})
However you can simplify this in a couple of ways.
You can do the utf-8 conversion with a list comprehension
You can also find the items ending in 'group' using endswith
You can use a negative slice to get the rest of the string without 'group'
That gets you down to:
group_nodes = [item.encode('utf-8') for item in cmds.ls(sl=True) if item.endswith('group')]
entries = [{
'type':'maya_file',
'name': "{0}V{1}{2}".format(shotName, versionStr, entry[:-5])
}
for entry in group_nodes]

Related

Copy value if it exists in Table 1 but not in Table 2

So essentially I have two tables. Table 1 has a list of all attendants to a certain event. Table 2 has a list of all members of an organization that attended said event. I'm trying to copy a list of all non-members that attended the event. So the logic in my head is trying to loop through Table 2 and see if the value also exists in Table 1. If it does not, I'm trying to copy it into a list.
var attendants = currentS.getRange("M2:M").getValues(); //this is the list of all members that attended an event
for (var x = 2; x <= checkLast; x++) {
newcheck = currentS.getRange(x,5).getValue(); //this is getting the name of the attendants
if (attendants.indexOf(newcheck) == -1) {
var columnM = currentS.getRange("M1:M").getValues(); //trying to see if name of attendants is in the list of all members that attended the event.
var columnMlast = columnM.filter(String).length;
var final = currentS.getRange(columnMlast+1,13);
final.setValue(currentS.getRange(x,5).getValue()); //if it attendant is not in the list of members that attended, copies the name into a new list.
Whenever I run the code, I end up just getting the whole list of attendants without anything being filtered out. I hope I'm clear, and thanks in advance!!
Explanation:
You can use the filter method to find the items of attendants that are not included in the list of members and that will result in the list of new_members that will be appended at the bottom of members.
Using this solution you don't need for loops and most importantly you don't need to use setValue and getValue in a loop which is computationally expensive.
Solution:
I can't use your code because you have variables that aren't defined in the code snippet you provided.
I will show you an example (sheet and code) that you can use to adjust your current solution.
Example Script:
function myFunction() {
const ss = SpreadsheetApp.getActive();
const currentS = ss.getSheetByName("Sheet1");
const members = currentS.getRange("M2:M").getValues().flat().filter(r=>r!='');
const attendants = currentS.getRange("N2:N").getValues().flat().filter(r=>r!='');
const new_members = attendants.filter(a=>!members.includes(a)).map(nm=>[nm]);
console.log(new_members) // output: [ [ 'guest1' ], [ 'guest2' ], [ 'guest3' ], [ 'guest4' ] ]
currentS.getRange(members.length+2,13,new_members.length,1).setValues(new_members);
}
Example sheet (Input-Output):

Google Apps Script: how to create an array of values for a given value by reading from a two column list?

I have a set of data in a Google spreadsheet in two columns. One column is a list of article titles and the other is the ID of a hotel that is in that article. Call it list1.
Example data
I would like returned a new list with article titles in one column, and an array of the hotel IDs in that article in the other column. Call it list2.
Example data
There are thousands of lines that this needs to be done for, and so my hope was to use Google Apps Script to help perform this task. My original thinking was to
Create column 1 of list2 which has the unique article titles (no script here, just the G-sheets =unique() formula.
Iterate through the titles in list2, looking for a match in first column of the list1
If there is a match:
retrieve its corresponding value in column 2
push it to an empty array in column two of list2
move onto next row in list1
if no longer a match, loop back to step 2.
I've written the following code. I am currently getting a type error (TypeError: Cannot read property '0' of undefined (line 13, file "Code")), however, I wanted to ask whether this is even a valid approach to the problem?
function getHotelIds() {
var outputSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('list2');
var lastRow = outputSheet.getLastRow();
var data = outputSheet.getRange(2,1,lastRow,2).getValues();
var workingSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('list1');
var lastActiveRow = workingSheet.getLastRow();
var itemIDS = [];
for (var i=1; i<=data.length; i++) {
var currentArticle = data[i][0];
var lookupArticle = workingSheet[i][0];
if (currentArticle === lookupArticle) {
var tempValue = [workingSheet[i][1]];
itemIDS.push(tempValue);
}
}
}
Use a simple google sheets formula:
You can use a very simple formula to achieve your goal instead of using long and complicated scripts.
Use =unique(list1!A2:A) in cell A2 of list2 sheet to get the unique hotels.
and then use this formula to all the unique hotels by dragging it down in column B.
=JOIN(",",filter(list1!B:B,list1!A:A=A2))
You got the idea right, but the logic needed some tweaking. The "undefined" error is caused by the workingSheet[i][0]. WorkingSheet is a Sheet object, not an array of data. Also, is not necessary to get the data from list2 (output), it is rather the opposite. You have to get the data from the list1 (source) sheet instead, and iterate over it.
I added a new variable, oldHotel, which will be used to compare each line with the current hotel. If it's different, it means we have reached a different Hotel and the data should be written in list2.
function getHotelIds() {
var outputSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('list2');
var outLastRow = outputSheet.getLastRow();
var workingSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('list1');
var lastActiveRow = workingSheet.getLastRow();
var sourceValues = workingSheet.getRange("A2:B" + lastActiveRow).getValues();
var itemIDS = [];
var oldHotel = sourceValues[0][0]; //first hotel of the list
for (var i = 0; i < sourceValues.length; i++) {
if (sourceValues[i][0] == oldHotel) {
itemIDS.push(sourceValues[i][1]);
/*When we reach the end of the list, the oldHotel variable will never be different. So the next if condition is needed. Otherwise it wouldn't write down the last Hotel.
*/
if (i == sourceValues.length - 1) {
outputSheet.getRange(outLastRow + 1, 1, 1, 2).setValues([
[sourceValues[i][0], itemIDS.toString()]
]);
}
} else {
outputSheet.getRange(outLastRow + 1, 1, 1, 2).setValues([
[sourceValues[i - 1][0], itemIDS.toString()]
]);
oldHotel = sourceValues[i][0]; //new Hotel will be compared
outLastRow = outputSheet.getLastRow(); //lastrow has updated
itemIDS = []; //clears the array to include the next codes
}
}
}
I also converted the itemIDS array to a String each time, so it's written down in a single cell without issues.
Make sure each column of the Sheet is set to "Plain text" from Format > Number > Plain Text
References
getRange
setValues
toString()

Filter core data items based on search text

I am trying to filter items based on text (mySearchText) from a search bar. So far I have got:
items = try context.fetch(Item.fetchRequest())
filtered data = items.filter { ($0.myArray?.contains(mySearchText))!}
This works if I enter the full text e.g. if I enter "Hello" into the search bar it will filter items with Hello in myArray.
However if I just enter "Hel" it won't filter the same item. How can I filter the items even if only a partial search term is used?
I want filteredData to be the items that have an array containing the string so
var filteredData: [Item] = []
e.g. if
item 1.myArray = ["cat", "dog", "monkey"] and
item 2.myArray = ["horse", "zebra", "cow"]
mySearchText = "o"
I would like filteredData to be item1 and item2 (cow in item 1 and dog in item 2 both contain "o")
You are calling contains() on an array which means you're not doing string matching but instead looking for objects equal to your mySearchText object, so your looking for objects equals to "Hello" or "Hel" in that array.
To do string matching instead you need to filter one level down so to speak. Here is my version where I assume myArray is an array of strings
items = try context.fetch(Item.fetchRequest())
var filteredData = [Item]()
for item in items {
if item.myArray?.filter({$0.contains(mySearchText)}).count > 0 {
filteredData.append(item)
}
}
Its work fine when i use the code below, maybe you should use string to filter based on it.
var mySearchText = "a"
var items = ["Adam", "Ahmad", "abdalla", "abcd", "efj", "hijk"]
let filtereddata = items.filter { ($0.lowercased().contains(mySearchText))}
print(filtereddata.count) // 4

MATLAB: Subindexing in cell array based on results of strfind

I have a cell array, like so:
ID = {'g283', 'sah378', '2938349dgdgf', 'g283'};
I also have some data that corresponds to these IDs.
Data = {'data1', 'data2', 'data3', 'data4'};
Let's say my current ID is g283, and I want to extract Data that matches this ID.
I do strfind(ID, 'g283') and get a result like so:
result = {[1], [], [], [1]}
I now want to extract the data from data and get this:
new_data = ['data1', 'datat4'] or equivalent.
However, cell arrays cannot be subindexed into, so I am wondering if there is an easy method to do this without looping. Thank you!
Let the input variables be defined as
ID = {'g283', 'sah378', '2938349dgdgf', 'g283'}; % ID
Data = {'data1', 'data2', 'data3', 'data4'}; % data
s = 'g283'; % current ID
You only need to apply isempty to test if each result of strfind contains a match or not. This can be done via cellfun, for example as follows:
ind = cellfun(#(x) ~isempty(strfind(x, s)), ID);
new_data = Data(ind);
If you are looking for the whole string (as opposed to a partial match), a simpler alternative is to use ismember:
ind = ismember(ID, s);
new_data = Data(ind);

Lua - How to check if list contains element

I need some help with my lua script for a game. I need to check if my inventory in the game contains any id from a list.
Here's a piece of my list:
local Game_Items = {
{id = 7436, name = "angelic axe", value = 5000},
{id = 3567, name = "blue robe", value = 10000},
{id = 3418, name = "bonelord shield", value = 1200},
{id = 3079, name = "boots of haste", value = 30000},
{id = 7412, name = "butcher's axe", value = 18000},
{id = 3381, name = "crown armor", value = 12000}
}
The following code might look a bit weird since you don't know what it's for, but it's basically this: the list above is a list of items in my game, and inside the game theres an inventory where you can keep items and stuff. Now I want to check if my inventory contains any of those IDs.
I tried adding 2 of the id's manually and it worked, but my list of items contains over 500 items in total and I don't want to write them all out. Is there a way to put the whole list and check if it's in there somehow?
if not table.contains({ 3035, 3043, Game_Items[id] }, tempItemCounter.id) then
This is what I tried so far. Those two first id's work 3035 and 3043, then I tried all my whole list and only check the Ids. but I dont know how to do that. That code does not work. Could anyone just help me include the whole list of id's in the table.contains ?
Basically wanna include my whole list in that line, without typing out all IDs manually.
Shouldn't Game_Items[id] work? Doesn't that mean all the "id" inside "Game_Items"?
Thanks!
No it doesn't mean that. If foo is a table, then foo[id] looks for a field in foo that is called whatever id refers to, such as a string (so if id is 1 you will get foo[1], if id is "bar" you will get foo.bar, etc).
You can't do it in one line, but you can create a function that will allow you to write your if condition. I'm not sure what tempItemCounter is but assuming that your inventory is a map of keys to entries of the form
inventory = {
[1234] = {....},
[1235] = {....},
...
}
where each integer key is unique, and assuming you want true only if all items are in inventory, then you could do this:
function isAllInInventory(items, inventory)
for i,item in ipairs(items) do
if inventory[item.id] == nil
return false
end
end
return true
end
if isAllInInventory(Game_Items, inventory) then
...
end

Resources