How to read/modify/remove items/lists contained in a list in applescript

纵饮孤独 提交于 2019-12-08 11:06:47

问题


This question follows on from my previous question How to transform a CSV into several lists (applescript)?

I have a csv file with about 4000 lines. I import it and make each line into an item of a list, I then make each line it's own list of items.

eg: (I am using numbers but the data I have contains text as well and most of the entries are more than 1 char, some entries are also blank)

1,2,3,4,5,6
6,5,4,3,2,1
7,8,9,0,7,6
3,4,4,5,3,1

becomes

{"1,2,3,4,5,6","6,5,4,3,2,1","7,8,9,0,7,6","3,4,4,5,3,1"}

becomes

{{"1","2","3","4","5","6"}{"6","5","4","3","2","1"}{"7","8","9","0","7","6"}{"3","4","4","5","3","1"}}

now what I would like to be able to do is the following:

Delete certain items from each list, so for example I want to delete the second Item from Each list, that's "2", "5", "8" and "4"

Run calculations on certain items, so for example I want to multiply item 5 by 2

Also some of the numbers in my data have the +11 or + 17 at the end of them, I would like to know how to replace that with the matching amount of zeros, so for example if i had 5002+6 I would want to make it into 5002000000

Current code is:

-- Choosing your file
set csvDevices to "testfile.csv"

-- Reading file to memory
set csvDevices to read csvDevices

-- Creating Records (Single Lines)
set csvDevicesRecords to paragraphs of csvDevices

-- Remove Title Line
set csvDevicesRecords to rest of csvDevicesRecords

-- Make each line into a list
set csvDevicesValues to {}
set AppleScript's text item delimiters to ","
repeat with i from 1 to length of csvDevicesRecords
    set end of csvDevicesValues to text items of (item i of csvDevicesRecords)
end repeat
set AppleScript's text item delimiters to ""

I hope the above all makes sense.


回答1:


It's really not hard if you write yourself a subroutine to do the stuff for you. Here's the 3 you requested. You'll need to add other subroutines so you can do other math operations (add, subtract, and divide). Just duplicate the multiplyItemNumberByValue() subroutine and change the operator to the appropriate one and it should work with no further changes.

Good luck.

set listOfLists to {{"1", "2+2", "3", "4", "5", "6"}, {"6", "5", "4", "3", "2", "1"}, {"7", "8", "9", "0", "7", "6"}, {"3", "4", "4", "5+3", "3", "1"}}

-- before performing any other operation, expand all zeros
set listOfLists to expandZeros(listOfLists)

-- remove item 2 from every sublist
set listOfLists to removeItemNumber(listOfLists, 2)

-- multiply item 1 of every sublist by 5
set listOfLists to multiplyItemNumberByValue(listOfLists, 1, 5)




(****************** SUBROUTINES ******************)
on multiplyItemNumberByValue(listOfLists, itemNumber, theValue)
    set newList to {}
    repeat with i from 1 to count of listOfLists
        set thisList to item i of listOfLists
        set thisItem to item itemNumber of thisList
        set newValue to (thisItem as number) * theValue
        set item itemNumber of thisList to (newValue as text)
        set end of newList to thisList
    end repeat
    return newList
end multiplyItemNumberByValue

on removeItemNumber(listOfLists, itemNumber)
    set newList to {}
    repeat with i from 1 to count of listOfLists
        set thisList to item i of listOfLists
        if itemNumber is equal to 1 then
            set newSublist to items 2 thru end of thisList
        else if itemNumber is equal to (count of thisList) then
            set newSublist to items 1 thru (itemNumber - 1) of thisList
        else
            set newSublist to items 1 thru (itemNumber - 1) of thisList & items (itemNumber + 1) thru end of thisList
        end if
        set end of newList to newSublist
    end repeat
    return newList
end removeItemNumber

on expandZeros(listOfLists)
    set newList to {}
    repeat with i from 1 to count of listOfLists
        set thisList to item i of listOfLists
        set newSublist to {}
        repeat with j from 1 to count of thisList
            set subItem to item j of thisList
            if subItem contains "+" then
                set x to offset of "+" in subItem
                if x is equal to 0 or x is equal to 1 or x is equal to (count of subItem) then
                    set end of newSublist to subItem -- do nothing
                else
                    set a to text 1 thru (x - 1) of subItem
                    set b to text (x + 1) thru end of subItem
                    repeat (b as number) times
                        set a to a & "0"
                    end repeat
                    set end of newSublist to a
                end if
            else
                set end of newSublist to subItem -- do nothing
            end if
        end repeat
        set end of newList to newSublist
    end repeat
    return newList
end expandZeros

Here's the other math subroutines...

on divideItemNumberByValue(listOfLists, itemNumber, theValue)
    set newList to {}
    repeat with i from 1 to count of listOfLists
        set thisList to item i of listOfLists
        set thisItem to item itemNumber of thisList
        set newValue to (thisItem as number) / theValue
        set item itemNumber of thisList to (newValue as text)
        set end of newList to thisList
    end repeat
    return newList
end divideItemNumberByValue

on addValueToItemNumber(listOfLists, itemNumber, theValue)
    set newList to {}
    repeat with i from 1 to count of listOfLists
        set thisList to item i of listOfLists
        set thisItem to item itemNumber of thisList
        set newValue to (thisItem as number) + theValue
        set item itemNumber of thisList to (newValue as text)
        set end of newList to thisList
    end repeat
    return newList
end addValueToItemNumber

on subtractValueFromItemNumber(listOfLists, itemNumber, theValue)
    set newList to {}
    repeat with i from 1 to count of listOfLists
        set thisList to item i of listOfLists
        set thisItem to item itemNumber of thisList
        set newValue to (thisItem as number) - theValue
        set item itemNumber of thisList to (newValue as text)
        set end of newList to thisList
    end repeat
    return newList
end subtractValueFromItemNumber



回答2:


Nigel Garvey's CSV-to-list converter is the best I have seen.

You can call it like this:

    set filePath to "/Users/You/Desktop/myCsv.csv"
    set csvData to do shell script "cat " & quoted form of filePath
    set csvDevicesLists to csvToList(csvData, {trimming:true})

--> {{"1", "2", "3", "4", "5", "6"}, {"6", "5", "4", "3", "2", "1"}, {"7", "8", "9", "0", "7", "6"}, {"3", "4", "4", "5", "3", "1"}}

You can pad zeros like this:

set xxx to {{"1", "2", "3+2", "4", "52+3", "6"}, {"6", "5", "4+5", "3", "2", "1"}}
repeat with i from 1 to count of xxx
    if (item i of xxx as text) contains "+" then
        set temp to {}
        repeat with anItem in item i of xxx
            set end of temp to (do shell script "echo " & quoted form of anItem & " | sed s/+/*10^/ | bc")
        end repeat
        set item i of xxx to temp
    end if
end repeat
return xxx

ASObjC Runner provides some good tools for manipulating lists as well.




回答3:


It would be easier to use Ruby or Python (or almost any other language):

"1,2,3+11,4,5,6
6,5,4,3,2,1+17".split("\n").each { |n|
  n.gsub!(/\+(\d+)/, "0" * $1.to_i)
  c = n.split(",")
  c[4] = c[4].to_i * 5
  c.delete_at(1)
  puts c.join(",")
}


来源:https://stackoverflow.com/questions/14963605/how-to-read-modify-remove-items-lists-contained-in-a-list-in-applescript

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!