frequent
frequent

Reputation: 28513

how to output a random file using Coldfusion cfdirectory and randRange functions?

I'm still trying to get my grips on Coldfusion...

I need to create a directy of files (say there are 10 files) and output 5 random files. Getting and outputting files is ok, but I'm not sure where to fit in the randrange. Here is my code:

 <cfdirectory action="list" directory="#expandpath("img/")#" filter="some*.*" name="dir">
     <!--- imgID --->
     <CFSET imgID= #RandRange(1, #dir.allRecords#)#>
     <!--- this only grabs the first 5 files --->
     <cfoutput query="dir" maxrows="5">
        <cfif FileExists("#expandpath("img/#name#")#")>
        <cfimage source="#expandpath("img/#name#")#" name="myImage">                                                   <cfif IsImage(myImage) is true>
          <cfset ImageSetAntialiasing(myImage,"on")>
              <cfset ImageScaleToFit(myImage,"highestQuality")>
              <!--- append to a list --->
          <li><cfimage source="#myImage#" action="writeToBrowser"></li>
           </cfif>               
        </cfif>
      </cfoutput>   

This works ok in displaying the first 5 images. However, I would like to have 5 random images.

Thanks for some insights!

EDIT:
This is how I ended up doing it - ONE QUESTION UNSOLVED -

<!-- get the directy, listinfo="name" because I only need filenames --->
<cfdirectory action="list" LISTINFO="name" directory="#expandpath(" logos/")#" filter="marke*.*" name="dir">

 <cfset images=[ ]>
 <!-- since dir is not indexable, like dir[pos], I need another array!-->
 <cfset dirArr=[ ]>
 <cfset blocker="false">
 <cfset maxLogos=5>
 <!-- fill new dirArr(ay) -->               
 <cfoutput query="dir">
    <cfset #ArrayAppend(dirArr, #expandpath( "logos/#name#")#)#>
 </cfoutput>
 <!-- loop -->
 <cfloop condition="blocker eq false">
    <-- random position -->
    <cfset pos=R andRange(1, #dir.recordcount#)>
    <cfif #dir.recordcount# eq 0 OR #ArrayLen(images)# gte #maxLogos#>
        <-- STOP loop -->
        <cfset blocker="true">
    </cfif>
    <cfset ArrayAppend(images, #dirArr[pos]#)>
    <!-- BROKEN unknown ARRAYDELETE --> 
    <!--- <cfset ArrayDelete(dirArr, #dirArr[pos]#)> --->
    <!-- IMG -->
    <cfimage source="#dirArr[pos]#" name="myImage">
    <cfif IsImage(myImage) is true>
        <cfoutput>
        <li data-icon="false">
           <cfimage source="#myImage#" action="writeToBrowser">
        </li>
        </cfoutput>
    </cfif>
 </cfloop>

The problem is the ArrayDelete does not work variable ARRAYDELETE is undefined, Coldfusion(8) tells me. Any idea what I'm doing wrong?

Upvotes: 1

Views: 1075

Answers (2)

Peter Boughton
Peter Boughton

Reputation: 112190

A simple alternative is to shuffle the array once and then take the first five items:

<cfset MaxLogos = 5 />
<cfset Images   = [] />
<cfset Files    = DirectoryList( expandPath("logos") , false, "name" , "marke*.jpg" ) />

<cfset createObject( "java", "java.util.Collections" ).shuffle( Files ) />

<cfloop index="i" from="1" to=#Min(MaxLogos,ArrayLen(Files))# >
    <cfset ArrayAppend( Images , Files[i] ) />
</cfloop>

<cfdump var=#Images# />

Upvotes: 3

Chris Blackwell
Chris Blackwell

Reputation: 2178

I'm not sure if your code will actually work as there appears to be several syntactical errors in it. Also you're doing a directory list on img but then pulling images from logos and you've not made it clear what the relationship is between these directories

those issues aside, here is how i would handle this.

<cfscript>
// this code is untested, but should get you going
// get list of image file names as an array
dir = directoryList(expandPath("imgs"), false, "name", "*.jpg");
images = [];
while(true) {
  // if out directory list is now empty or we have 5 results, we're done
  if(!arrayLen(dir) or arrayLen(images) gte 5) break;
  // get an image from a random point in the list
  pos = randrange(1, arrayLen(dir));
  // append it to our images array
  arrayAppend(images, dir[pos]);
  // delete form the source array, this avoids duplicates in further iterations
  arrayDeleteAt(dir, pos);
}
</cfscript>

This gives you an array of images, with between 0 and 5 elements, which you can then output as a list.

As a side note, its not advisable to use <cfimage> and related functions repeatedly. If you need to resize or manipulate an image you should then cache it back to disk rather than repeating the manipulation every request.

Upvotes: 1

Related Questions