Apply a lambda function to filter out elements of a list.

 list filter( list input , lambda definition )

Evaluates a lambda for every element in the list, and returns a new list with only the elements that evaluated to true.

If you are filtering on a data feed, you should instead use filter_content() to preserve the location of items that were pinned to specific feed locations with Recommendation Manager.


Include only those items that are greater than 2:

{content = filter([1, 2, 3, 4, 5], lambda x: x>2)} ---> [3, 4, 5]
Filter out pieces of content that are tagged “explicit-content”, including pinned items:
{content = filter(content, lambda x: !contains(x.tags, 'explicit-content'))}

Note that if you are filtering on a data feed, filter_content() works the same way as filter(), but preserves pinning locations. See filter_content() for additional feed filtering examples.

Display the Intersection of User-Interested and Trending Content

Use Case: Using collaborative filtering, you wish to find all items that are “trending” in your Content Library, but you only want to display the top three of those items to users based on user interest data from your Content Library. Used in conjunction with the personalize() function.


{**Find 100 items a user is interested in and 100 items that are popular**}
{interestContent = personalize({"algorithm":"interest","size":100})}
{popularContent = personalize({"algorithm":"popular", "size":100})}

{**Desired number of items**}
{recNum = 10}

{**FInd the intersect of the popular and interested items**}
{personalizedContent = content_intersect(interestContent,popularContent)}

{**Create a backup length if there are less than the number of desired item**}
{backupLength = recNum - length(personalizedContent)}

{**If the length of backup items is greater than 0, find unique content in the interestContent object to backfill the remaining items**}

{if backupLength > 0}

{usedcontent = []}
{personalizedContent = filter(personalizedContent, lambda c: (contains(usedcontent, c.url) ? false : push("usedcontent", c.url) || true))}
{backupContent = filter(interestContent, lambda c: (contains(usedcontent, c.url) ? false : push("usedcontent", c.url) || true))}

{backupContent = personalize({
"algorithm" : "interest",
"size": backupLength,
"content" : backupContent

{personalizedContent = personalizedContent + backupContent}


{**Run personalization**}
{personalizedContent = personalize({
"algorithm" : "interest",
"size": 10,
"content" : personalizedContent

In the Code:

<p>Here are hot items we think you'll love</p>
{foreach personalizedContent as c}


Here are hot items with think you’ll love

Item 1

Item 2

Item 3


This script uses the personalize() function to recommend content based on two algorithms: Interest (based on on-site browsing) and what’s popular (pieces of content that have the most purchases or the most pageviews). It starts by creating two content objects based on those algorithms: One called “interestContent”, which finds 100 items a user has displayed personal interest in; and one called “popularContent”, which is the 100 globally most popular items. Ultimately, you want an overlap of ten items to show to each user (i.e., ten items that they are interested in that are also most popular), and that recommendation length is set in the “recNum” assignment. Next, in order to find the overlap between the two, the content_intersect() function is used to find how much content exists between “interestContent” and “popularContent”, which creates a new content object called “personalizedContent”. Next, there’s a check of the length of this object (i.e., exactly how many items existed in both sections). This number is subtracted from the “recNum” value, which creates the “backupLength”. This means if there are only three matching items between the interested and popular content objects, the backupLength is “7”, meaning the script will now find seven additionally items to recommend. 

To check whether or not backup content is necessary, the next part of the script uses an “if” statement to check if the backupLength is greater than 0. If it is, a dedupe script is run, which uses the contains() function to check the title of every item in a data feed against an array called “usedcontent.” If the title of the item exists in the array, the filter() function removes it from the feed (this means that the title already occurred once, and it is a duplicated item). In this example, the filter is performed twice: Once on the “personalizedContent” object, and once on the original “interestContent” object. This second filter is used to create a “backupContent” object, which is the content a user is interested in that’s not in the “popularContent” object. The personalize() function is then run on the “backupContent” object baesd on user interest, and the value of the “backupLength” number (i.e. the number of additional items needed to make it to 10) will determine how many additional items to return. “personalizedContent” is then reassigned to be the other “personalizedContent” object plus the “backupContent”. If there were 10 items or more in the original “personalizedContent” object, then no backup content gets added.

Finally, personalize() is run on “personalizedContent” to get the top ten items for each user, which is then looped through using a “foreach” loop and displayed in the template.

Prompt Signup to Non-Subscribed Lists

Use Case: You manage your lists based on user variables and a Smart List (ex. Your  Technology List criteria is: Member of Master List, tech = 1). You’d like a one-click signup in each email for your users to add themselves to other lists based on user interest. You can do this by maintaining an array of your lists.


In the Setup:

{yourLists = []}

{foreach allLists as c}
{if profile.vars[c.var] == 1 || profile.vars[c.var] == "1"}
{push("yourLists", c.list)}

{listDelta = filter(allLists, lambda c: !contains(yourLists, c.list))}

In the Code:

<!--Showing only lists users are interested in-->
 {foreach listDelta as c}
 {if horizon_interest(c.tags) >= 2}
 Click here to sign up to <a href="[{c.var}]=1">{c.list}</a>!<br/>


Click here to sign up to Books!

Click here to sign up to Tech!

Click here to sign up to Politics!

Click here to sign up to Science!


This script uses an array called “allLists”, which each item is an object with applicable interest tags (optional), the list name, and corresponding variable. An empty array called “yourLists” is then created, a foreach loop then iterates through the allLists array and checks the “profile” object. If the user has that corresponding custom field on their profile and it equals “1” in either the string or numerical data type, the list name gets pushed into the yourLists array, using the push() function. For instance, if a user has the “books” custom field equaling “1” on their profile, the “Books” list is added to their array.

Next, a local variable called “listDelta” is created, which users the filter() function to filter through the allLists array, keeping anything that’s not contained in the yourLists array, by using a bang (“!”), which acts as a “not statement,” in conjunction with the contains() function.

The listDelta array is then looped through in the Code. Using the horizon_interest function, the value of each tag is evaluated on a user-by-user basis. lf their interest score in that tag is greater than “2”, they will be prompted to sign up for that particular list, with the variable name automatically populating as the value of the “sailthru_vars” query parameter, which sets a custom field on a user upon click. When the user clicks, the variable us placed on their profile with the value of “1”, i.e. “science = 1”.

Filter Out Content with Empty ‘Image’ URL Value

Use Case: You discover that some of your content has an image field where the value is an empty string instead of an image URL. Since Sailthru recognizes the presence of the sailthru.image tag, it won’t be filtered out at the feed level. Thankfully, you can use Zephyr to filter out any content that doesn’t have an actual value for the image.


In the Setup:

{content = filter(content, lambda c: length(c.image) > 0)}

In the example Media feed, the “Spider-Man: Threat or Menace?” article would be thus excluded as its “sailthru.image” parameter is an empty string.

Explanation: This script uses a lambda, which creates an anonymous function, in conjunction with the length() function to check the “image” field of each item in a content array to see if the length is greater than 1, or in other words, if there’s a value. If there isn’t, the filter() function will remove it from the “content” object. This is beneficial if there’s a chance that you might spider an empty string for the sailthru.image parameter.