Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
0

Sort Objects by number script

Explorer ,
Jan 03, 2020 Jan 03, 2020

I currently use a script that sorts object by number. However, it doesn't play nice when I have single, double, and triple digits within the same layer. Is there a way to modify this script so that when I run it, it will sort numbers accuratly?

Screen Shot 2020-01-03 at 7.00.56 AM.pngexpand image

 

 
var layers = activeDocument.activeLayer;
var objArray = []; // array to stuff items into - universal

var layPI = layers.pathItems; // for the path items - can be changed to whatever we want to sort
var len = layPI.length; // number of path items
 
// for handling duplicates:
//var current, last; // for holding the last 2 items sorted
var numDuplicates = 0;


// store all path items in an array
for (var i = 0; i < len; i++)
{
objArray.push(layPI[i]); // filling the array
}
 
// sort layer top to bottom
objArray.sort();

// now, replace items in path with reordered array
for (i = 0; i < len; i++)
{
objArray[i].move(layPI[i], ElementPlacement.PLACEBEFORE);

// now, find duplicates
if(i!=0) // won't run the first time (to avoid array position -1)
{

// compare last and current, and augment number of duplicates for final count
if(layPI[i].name == layPI[i-1].name)
{
 
numDuplicates++; // increment the # of duplicates tracked
}
}
}

// spit out the proper message based on results
alert("The active layer has been sorted. \nThere were "+len+" items and "+numDuplicates+" duplicates.");
TOPICS
Scripting , Tools , Type
2.1K
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Enthusiast , Jan 03, 2020 Jan 03, 2020

Hi, here's how I would do it:

 

function sortLayerContentAlphanumerically() {
    Array.prototype.forEach = function (callback) {
        for (var i = 0; i < this.length; i++)
            callback(this[i], i, this);
    };
    var layer = app.activeDocument.activeLayer;
    var items = []
    for (var i = 0; i < layer.pageItems.length; i++)
        items.push(layer.pageItems[i])
    items.sort(function (a, b) {
        if (a.name.length === b.name.length) return a.name.localeCompare(b.name)
      
...
Translate
Adobe
Enthusiast ,
Jan 03, 2020 Jan 03, 2020

Hi, here's how I would do it:

 

function sortLayerContentAlphanumerically() {
    Array.prototype.forEach = function (callback) {
        for (var i = 0; i < this.length; i++)
            callback(this[i], i, this);
    };
    var layer = app.activeDocument.activeLayer;
    var items = []
    for (var i = 0; i < layer.pageItems.length; i++)
        items.push(layer.pageItems[i])
    items.sort(function (a, b) {
        if (a.name.length === b.name.length) return a.name.localeCompare(b.name)
        else if (a.name.length < b.name.length) return -1
        else if (a.name.length > b.name.length) return 1;
    })
    items.forEach(function (item) {
        item.move(layer, ElementPlacement.PLACEATEND)
    })
}

sortLayerContentAlphanumerically();

 

If you want your original function to work, then you'd just need to expand on .sort(). By default this returns alphanumerically by the first digit, but you'd need to do something similar to my own sort function where I look at each object (a + b) and return either 1, 0, or -1 so it knows to place it before or after. We know that any thing with 3 digits is greater than anything with 2, so always return either -1 or 1 in this instance, but if each object has the same digits we're free to sort them through a String.prototype.localeCompare (which itself returns numeric values like 1, 0, or -1).

 

Bear in mind this assumes all objects are strictly numerically named. You could pretty easily modify it so it handles things like "Layer 29" or "Item 28", etc., but given your current file I didn't feel like that would be needed.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Jan 03, 2020 Jan 03, 2020

This is great, thank you!

 

I do sometimes have to use letters either before or after, ie A201, B201, or 208A, 208B. Does this script work for that, or would it goof it up? It never gets much more complex than that.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Jan 03, 2020 Jan 03, 2020

Hi, it would be easy to work that in. Try this one instead, which uses Regex to extract the number from the layer name and compares only the numeric digits:

 

function sortLayerContentAlphanumerically() {
    Array.prototype.forEach = function (callback) {
        for (var i = 0; i < this.length; i++)
            callback(this[i], i, this);
    };
    var layer = app.activeDocument.activeLayer, items = [];
    for (var i = 0; i < layer.pageItems.length; i++)
        items.push(layer.pageItems[i])
    items.sort(function (a, b) {
        if (/\d/.test(a.name) && /\d/.test(b.name)) {
            var aNum = a.name.match(/\d{1,}/)[0], bNum = b.name.match(/\d{1,}/)[0]
            if (aNum.length === bNum.length) return aNum.localeCompare(bNum)
            else if (Number(aNum) < Number(bNum)) return -1
            else if (Number(aNum) > Number(bNum)) return 1;
        } else return -1;
    })
    items.forEach(function (item) {
        item.move(layer, ElementPlacement.PLACEATEND)
    })
}

sortLayerContentAlphanumerically();

 

This should work for anything that has "a20" or "barrel8", but not two sets of digits like "Layer 20 Copy 39", etc.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Jan 06, 2020 Jan 06, 2020

This is incredibly helpful, and I really appreciate your help.

 

I was testing the script and I came across a somewhat fringe case where I have two of the same numbers with different letters. i.e. 2A, 2B, 3A, 3B, 4A, 4B. Luckily it's rather rare and few enough that it's not terribly time consuming to just manually adjust the ones that fall out of order. Typically the letters come before the numbers, but not always.

 

Would it be difficult to add in a way to have it sort these in that manner as well? I attached a picture of a test case after running the script.

Screen Shot 2020-01-06 at 8.00.56 AM.pngexpand image

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Jan 06, 2020 Jan 06, 2020

Sure, can you post a list of all possible names and their intended order?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Jan 06, 2020 Jan 06, 2020
LATEST

https://docs.google.com/spreadsheets/d/1l7i-KyV8CfUgJTPrkSNmX5wiuRO5I0SiUlkgoVuv8uY/edit?usp=sharing

 

Here's a link to a spreadsheet I've been using for testing. This is an extreme example, but it's in the order that would be needed. For the duplicate numbers that have different letters, which I've marked with green, they could be in the order I have them now (A16, A17, ..., B16, B17, ...) or they could be done like this: A16, B16, A17, B17, ect. Whatever is easiest that doesn't mess other things up. 

I recognize that something like this can get pretty tricky, sorting has been a real thorn for what I've been doing.

This browser version is no longer supported. Please upgrade to a supported browser.
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines